代码拉取完成,页面将自动刷新
同步操作将从 方舟编译器孵化器/clang2mpl 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
/*
* Copyright (c) 2021 Futurewei Technologies, Inc.
*
* clang2mpl is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan
* PSL v2. You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
* NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. See the
* Mulan PSL v2 for more details.
*/
#include "Clang2MapleVisitor.h"
#include "Clang2MapleOptions.h"
#include "clang/AST/APValue.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/SmallVector.h"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunknown-warning-option"
#pragma GCC diagnostic ignored "-Wcast-qual"
#pragma GCC diagnostic ignored "-Wignored-qualifiers"
#pragma GCC diagnostic ignored "-Wreturn-type"
#pragma GCC diagnostic ignored "-Woverloaded-virtual"
#pragma GCC diagnostic ignored "-Wunused-variable"
#pragma GCC diagnostic ignored "-Wsign-compare"
#pragma GCC diagnostic ignored "-Wpedantic"
#pragma GCC diagnostic ignored "-Wtype-limits"
#pragma GCC diagnostic ignored "-Wcovered-switch-default"
#pragma GCC diagnostic ignored "-Wsuggest-override"
#include "bin_mplt.h"
#include "mir_symbol.h"
#include "mir_type.h"
#include "mpl_logging.h"
#include "opcode_info.h"
#pragma GCC diagnostic pop
#if defined __has_cpp_attribute
#if __has_cpp_attribute(clang::fallthrough)
#define FALLTHROUGH [[clang::fallthrough]]
#else
#define FALLTHROUGH
#endif
#else
#define FALLTHROUGH
#endif
using namespace maple;
static MIRStorageClass StorageClass2Mpl(clang::StorageClass SC);
static Opcode BinOpcode2Mpl(clang::BinaryOperatorKind Op, bool isSigned);
static bool isAssign(Opcode Op);
static bool isPointerType(MIRType *Ty);
#ifdef DEBUG
namespace maple {
extern MIRModule *theMIRModule;
}
#endif // DEBUG
MIRSymbol *Clang2MapleVisitor::VisitTranslationUnitDecl(
const clang::TranslationUnitDecl *TU) {
Context = &TU->getASTContext();
setupBuiltinTypes();
// Initial setup for Maple
// Get source file
clang::FileID MainFileID = Context->getSourceManager().getMainFileID();
const clang::FileEntry *MainFile =
Context->getSourceManager().getFileEntryForID(MainFileID);
// Set source language
Module = new MIRModule(MainFile->getName().str().c_str());
Module->SetCurFunction(nullptr);
#ifdef DEBUG
theMIRModule = Module;
#endif // DEBUG
Module->SetSrcLang(Context->getLangOpts().CPlusPlus ? kSrcLangCPlusPlus
: kSrcLangC);
// TODO: Do we need to setup the source files here? see whirl2mpl.cxx:2879
Builder = new MIRBuilder(Module);
// Create the builtin va_list type
clang::TypedefDecl *VaListTypeDef = Context->getBuiltinVaListDecl();
if (VaListTypeDef->isReferenced()) {
Visit(VaListTypeDef->getUnderlyingType()->getAsRecordDecl());
}
// Visit all of the top-level children
for (auto child = TU->decls_begin(); child != TU->decls_end(); ++child) {
if (!child->isImplicit()) {
Visit(*child);
}
}
// Finalize the module
Module->SetFlavor(kFeProduced);
Module->SetNumFuncs(Module->GetFunctionList().size());
if (UseAscii) {
Module->OutputAsciiMpl("", ".mpl");
} else {
BinaryMplt BinMplt(*Module);
std::string ModuleName = Module->GetFileName();
std::string::size_type LastDot = ModuleName.find_last_of(".");
std::string BaseName = ModuleName.substr(0, LastDot);
BinMplt.GetBinExport().not2mplt = true;
BinMplt.Export(BaseName + ".bpl");
}
return nullptr;
}
//
// Visit Decls
//
// Visit TypeDecls
MIRSymbol *Clang2MapleVisitor::VisitTypeDecl(const clang::TypeDecl *Ty) {
LogInfo::MapleLogger() << "Warning: Unhandled type decl\n";
Ty->dump();
return nullptr;
}
MIRSymbol *
Clang2MapleVisitor::VisitRecordDecl(const clang::RecordDecl *Record) {
// If there is not a complete definition, or this is not it, skip it.
if (!Record || !Record->isCompleteDefinition() ||
!Record->isThisDeclarationADefinition()) {
return nullptr;
}
// If this record has already been fully defined, skip it.
clang::QualType RecTy = Context->getRecordType(Record);
auto it = TypeMap.find(RecTy.getTypePtr());
if (it != TypeMap.end()) {
MIRStructType *STy = static_cast<MIRStructType *>(
GlobalTables::GetTypeTable().GetTypeFromTyIdx(it->second));
if (!STy->IsIncomplete()) {
return nullptr;
}
}
// Process any decls inside of this record (inner struct)
clang::DeclContext *DC = clang::TagDecl::castToDeclContext(Record);
for (const auto *D : DC->decls()) {
if (auto Inner = llvm::dyn_cast<clang::RecordDecl>(D)) {
Visit(Inner);
}
}
std::string TypeName = Record->getName().str();
if (TypeName.empty()) { // Anonymous struct
TypeName = "_anon" + std::to_string(++UnnamedCount);
} else if (TypeName[0] == '.') {
TypeName[0] = '_';
}
const clang::Type *StructTy = Record->getTypeForDecl();
MIRStructType Struct(StructTy->isUnionType() ? kTypeUnion : kTypeStruct);
FieldVector Fields;
for (const auto *I : Record->fields()) {
clang::QualType FieldQT = I->getType();
TyIdx FieldTyIdx = type2MplIdx(FieldQT);
FieldAttrs Attrs;
TyIdxFieldAttrPair TyAttrPair;
clang::CharUnits Alignment = Context->getDeclAlign(I);
if (Alignment > Context->toCharUnitsFromBits(
Context->getTypeUnadjustedAlign(FieldQT))) {
Attrs.SetAlign(Alignment.getQuantity());
}
if (FieldQT.isVolatileQualified()) {
Attrs.SetAttr(FLDATTR_volatile);
}
if (FieldQT.isRestrictQualified()) {
Attrs.SetAttr(FLDATTR_restrict);
}
if (FieldQT.isConstQualified()) {
Attrs.SetAttr(FLDATTR_const);
}
if (I->isBitField()) {
MIRType *FieldTy =
GlobalTables::GetTypeTable().GetTypeFromTyIdx(FieldTyIdx);
unsigned BitWidth = I->getBitWidthValue(*Context);
MIRBitFieldType BitFieldTy(BitWidth, FieldTy->GetPrimType());
FieldTyIdx = GlobalTables::GetTypeTable().GetOrCreateMIRType(&BitFieldTy);
}
TyAttrPair = std::make_pair(FieldTyIdx, Attrs);
std::string FieldName(I->getName().str());
if (FieldName.empty()) {
FieldName = "_no.name" + std::to_string(++UnnamedCount);
} else if (FieldName[0] == '.') {
FieldName[0] = '_';
}
GStrIdx FieldStrIdx =
GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(FieldName);
Fields.push_back(std::make_pair(FieldStrIdx, TyAttrPair));
}
Struct.SetFields(Fields);
recordFieldIDs(Record, Record, 0);
MIRType *MTy = GlobalTables::GetTypeTable().GetOrCreateMIRTypeNode(Struct);
GStrIdx StrIdx =
GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(TypeName);
MTy->SetNameStrIdx(StrIdx);
Module->GetTypeNameTab()->SetGStrIdxToTyIdx(StrIdx, MTy->GetTypeIndex());
Module->PushbackTypeDefOrder(StrIdx);
TypeMap[StructTy] = MTy->GetTypeIndex();
// If this record was referenced while it was incomplete, update the pointer
// type.
auto UT = UnresolvedTypes.find(Record);
if (UT != UnresolvedTypes.end()) {
UT->second->SetPointedTyIdx(MTy->GetTypeIndex());
}
return nullptr;
}
MIRSymbol *
Clang2MapleVisitor::VisitTypedefDecl(const clang::TypedefDecl *Typedef) {
return nullptr;
}
// Visit VarDecls
MIRSymbol *Clang2MapleVisitor::VisitVarDecl(const clang::VarDecl *Var) {
std::string Name = Var->getName().str();
if (Name[0] == '.') {
Name[0] = '_';
}
MIRType *Ty = type2Mpl(Var->getType());
MIRSymbol *Symbol;
if (Var->isLocalVarDecl()) {
if (Var->hasExternalStorage()) {
// If it is referring to an existing global, use it, else create it.
Symbol = Builder->GetGlobalDecl(Name);
if (!Symbol) {
Symbol = Builder->CreateGlobalDecl(Name, *Ty);
}
} else {
// If a local with this name already exists (from a different scope),
// append a number so that they are unique.
if (Builder->GetLocalDecl(Name)) {
Name = Name + "." + std::to_string(++UnnamedCount);
}
Symbol = Builder->CreateLocalDecl(Name, *Ty);
if (Var->isStaticLocal()) {
Symbol->SetStorageClass(kScPstatic);
if (Var->hasInit()) {
Symbol->SetKonst(getInitializer(Ty, Var->getInit()));
}
}
}
} else { // Global
MIRConst *Init = nullptr;
if (Var->hasInit()) {
Init = getInitializer(Ty, Var->getInit());
}
Symbol = Builder->CreateGlobalDecl(
Name, *Ty, StorageClass2Mpl(Var->getStorageClass()));
Symbol->SetKonst(Init);
if (Var->isWeak()) {
Symbol->SetAttr(ATTR_weak);
}
}
if (Var->getType().isConstQualified()) {
Symbol->SetAttr(ATTR_const);
}
if (!Var->getType()->isIncompleteType()) {
int64_t NaturalAlignment =
Context
->toCharUnitsFromBits(
Context->getTypeUnadjustedAlign(Var->getType()))
.getQuantity();
// Get alignment from the decl
TypeAttrs Attrs = Symbol->GetAttrs();
if (unsigned int AlignmentBits = Var->getMaxAlignment()) {
unsigned int Alignment = AlignmentBits / 8;
if (Alignment > NaturalAlignment) {
Attrs.SetAlign(Alignment);
}
}
// Get alignment from the type
if (unsigned int AlignmentBits =
Context->getTypeAlignIfKnown(Var->getType())) {
unsigned int Alignment = AlignmentBits / 8;
if (Alignment > Attrs.GetAlign() && Alignment > NaturalAlignment) {
Attrs.SetAlign(Alignment);
}
}
Symbol->SetAttrs(Attrs);
}
Symbol->SetSKind(kStVar);
SrcPosition Pos = sourceLocation2Mpl(Var->getLocation());
Symbol->SetSrcPosition(Pos);
DeclMap.insert({Var, Symbol});
return Symbol;
}
MIRSymbol *Clang2MapleVisitor::VisitParmVarDecl(const clang::ParmVarDecl *Var) {
MIRType *Ty = type2Mpl(Var->getType());
std::string Name = Var->getName().str();
if (Name.empty()) {
Name = "arg|" + std::to_string(Var->getFunctionScopeIndex());
}
if (Var->isKNRPromoted()) {
Name = Name + ".kr";
}
MIRSymbol *Symbol = Builder->GetOrCreateLocalDecl(Name, *Ty);
Symbol->SetStorageClass(kScFormal);
SrcPosition Pos = sourceLocation2Mpl(Var->getLocation());
Symbol->SetSrcPosition(Pos);
DeclMap.insert({Var, Symbol});
return Symbol;
}
MIRSymbol *
Clang2MapleVisitor::VisitFunctionDecl(const clang::FunctionDecl *Func) {
std::string Name = Func->getName().str();
if (Name[0] == '.') {
Name[0] = '_';
}
TyIdx FuncTyIdx = type2MplIdx(Func->getType());
MIRFuncType *FuncType = static_cast<MIRFuncType *>(
GlobalTables::GetTypeTable().GetTypeFromTyIdx(FuncTyIdx));
MIRSymbol *FuncSym = GlobalTables::GetGsymTable().CreateSymbol(kScopeGlobal);
GStrIdx StrIdx = Builder->GetOrCreateStringIndex(Name);
FuncSym->SetNameStrIdx(StrIdx);
GlobalTables::GetGsymTable().AddToStringSymbolMap(*FuncSym);
FuncSym->SetStorageClass(kScText);
FuncSym->SetSKind(kStFunc);
SrcPosition Pos = sourceLocation2Mpl(Func->getLocation());
FuncSym->SetSrcPosition(Pos);
MIRFunction *MFunc = Builder->GetCurrentFuncCodeMp()->New<MIRFunction>(
Module, FuncSym->GetStIdx());
MFunc->SetMIRFuncType(FuncType);
MIRType *RetTy =
GlobalTables::GetTypeTable().GetTypeFromTyIdx(FuncType->GetRetTyIdx());
MIRType *OrigRetTy = type2Mpl(Func->getReturnType());
MFunc->SetReturnStruct(*RetTy);
MFunc->SetPuidx(GlobalTables::GetFunctionTable().GetFuncTable().size());
MFunc->SetPuidxOrigin(MFunc->GetPuidx());
if (Func->isVariadic()) {
MFunc->SetVarArgs();
}
GlobalTables::GetFunctionTable().GetFuncTable().push_back(MFunc);
FuncSym->SetTyIdx(FuncTyIdx);
FuncSym->SetFunction(MFunc);
if (Func->isWeak()) {
FuncSym->SetAttr(ATTR_weak);
MFunc->SetAttr(FUNCATTR_weak);
}
if (Func->isStatic()) {
MFunc->SetAttr(FUNCATTR_static);
}
MIRFunction *LastFunc = Module->CurFunction();
Module->SetCurFunction(MFunc);
Builder->SetCurrentFunction(*MFunc);
MFunc->AllocSymTab();
MFunc->AllocPregTab();
MFunc->AllocTypeNameTab();
MFunc->AllocLabelTab();
DeclMap.insert({Func, FuncSym});
unsigned int firstParam = 0;
if (OrigRetTy->GetSize() > 16) {
MFunc->SetFirstArgReturn();
firstParam = 1;
MIRType *RetAddrTy = GlobalTables::GetTypeTable().GetTypeFromTyIdx(
FuncType->GetNthParamType(0));
MIRSymbol *Symbol = Builder->GetOrCreateLocalDecl("retval.0", *RetAddrTy);
Symbol->SetStorageClass(kScFormal);
SrcPosition Pos = sourceLocation2Mpl(Func->getLocation());
Symbol->SetSrcPosition(Pos);
FormalDef RetVal(Symbol->GetNameStrIdx(), Symbol, RetAddrTy->GetTypeIndex(),
TypeAttrs());
MFunc->AddFormalDef(RetVal);
}
size_t NumParams = FuncType->GetParamTypeList().size();
for (uint32 i = firstParam; i < NumParams; i++) {
MIRSymbol *Param = Visit(Func->getParamDecl(i - firstParam));
FormalDef FormalDef(Param->GetNameStrIdx(), Param,
FuncType->GetNthParamType(i),
FuncType->GetNthParamAttrs(i));
MFunc->AddFormalDef(FormalDef);
}
if (Func->isThisDeclarationADefinition() && Func->hasBody()) {
BlockNode *FuncBody = Builder->GetCurrentFuncCodeMp()->New<BlockNode>();
// Insert conversions for K&R style parameters
for (uint32 i = firstParam; i < NumParams; i++) {
const clang::ParmVarDecl *Parm = Func->getParamDecl(i - firstParam);
if (Parm->isKNRPromoted()) {
MIRType *ParmTy = type2Mpl(Parm->getType());
MIRType *KRTy = MFunc->GetNthParamType(i);
// Create a new local with the correct type.
MIRSymbol *ParmSym =
Builder->GetOrCreateLocalDecl(Parm->getNameAsString(), *ParmTy);
// Convert from the K&R type to the parameter's type.
StmtNode *ParmInit = Builder->CreateStmtDassign(
*ParmSym, 0,
Builder->CreateExprTypeCvt(
OP_cvt, *ParmTy, *KRTy,
Builder->CreateExprDread(*KRTy, 0,
*MFunc->GetFormalDefAt(i).formalSym)));
FuncBody->AddStatement(ParmInit);
// Update the map so that uses of the parameter use this new symbol.
DeclMap[Parm] = ParmSym;
}
}
// Insert function body
BlockNode *Body =
static_cast<BlockNode *>(Visit(Func->getBody()).getNode());
FuncBody->AppendStatementsFromBlock(*Body);
MFunc->SetBody(FuncBody);
if (VerifyMaple) {
FuncBody->Verify();
}
// If the last instruction of the body is not a return, add a return, with a
// zero value if there is a non-void return type.
if (!FuncBody->GetLast() || FuncBody->GetLast()->GetOpCode() != OP_return) {
BaseNode *RetVal = nullptr;
if (RetTy->GetPrimType() != PTY_void) {
if (!RetTy->IsScalarType()) {
RetTy = GlobalTables::GetTypeTable().GetUInt32();
}
MIRConst *Zero = createZero(RetTy);
RetVal = Builder->CreateConstval(Zero);
}
NaryStmtNode *Return = Builder->CreateStmtReturn(RetVal);
FuncBody->AddStatement(Return);
}
}
Module->AddFunction(MFunc);
Module->SetCurFunction(LastFunc);
return FuncSym;
}
MIRSymbol *Clang2MapleVisitor::VisitEnumDecl(const clang::EnumDecl *Enum) {
// Enums are just converted to constants when used, so do nothing here
return nullptr;
}
MIRSymbol *Clang2MapleVisitor::VisitEnumConstantDecl(
const clang::EnumConstantDecl *EnumConst) {
// Enums are just converted to constants when used, so do nothing here
return nullptr;
}
//
// Visit Statements
//
Result Clang2MapleVisitor::VisitStmt(const clang::Stmt *S) {
LogInfo::MapleLogger() << "Warning: Unhandled statement\n";
S->dump();
return Result(S->getBeginLoc());
}
Result Clang2MapleVisitor::VisitCompoundStmt(const clang::CompoundStmt *CS) {
BlockNode *Block = Builder->GetCurrentFuncCodeMp()->New<BlockNode>();
for (clang::Stmt *S : CS->body()) {
Result Res = Visit(S);
addToBlock(Block, Res);
}
return Result(Block, CS->getBeginLoc());
}
Result Clang2MapleVisitor::VisitDeclStmt(const clang::DeclStmt *DS) {
Result Res(DS->getBeginLoc());
for (const auto *D : DS->decls()) {
MIRSymbol *Sym = Visit(D);
if (const clang::VarDecl *VD = llvm::dyn_cast<clang::VarDecl>(D)) {
if (VD->hasInit() && VD->isLocalVarDecl() && !VD->isStaticLocal()) {
const clang::Expr *InitExpr = VD->getInit();
Result InitRes = Visit(InitExpr);
BaseNode *Init = getNodeAsRVal(InitRes);
Res.appendStmts(InitRes);
if (!Init) {
continue;
}
if (Sym->GetType()->GetKind() == kTypeStruct ||
Sym->GetType()->GetKind() == kTypeUnion) {
MIRStructType *StructTy =
static_cast<MIRStructType *>(Sym->GetType());
assignStruct(Res, Sym, nullptr, StructTy, Init);
} else if (Sym->GetType()->GetKind() == kTypeArray) {
MIRArrayType *ArrayTy = static_cast<MIRArrayType *>(Sym->GetType());
AddrofNode *BaseAddr = Builder->CreateExprAddrof(0, *Sym);
BaseAddr->SetPrimType(PointerPrimTy);
assignArray(Res, BaseAddr, ArrayTy, Init);
} else {
DassignNode *Assign =
Builder->CreateStmtDassign(Sym->GetStIdx(), 0, Init);
Assign->SetSrcPos(sourceLocation2Mpl(DS->getBeginLoc()));
Res.appendStmtBefore(Assign);
}
}
} else if (llvm::isa<clang::TypedefDecl>(D)) {
// Safely ignore typedefs
return Res;
} else {
LogInfo::MapleLogger() << "Warning: Non-VarDecl in DeclStmt\n";
D->dump();
}
}
return Res;
}
Result Clang2MapleVisitor::VisitDoStmt(const clang::DoStmt *Do) {
WhileStmtNode *WhileNode =
Builder->GetCurrentFuncCodeMp()->New<WhileStmtNode>(OP_dowhile);
Result Res(WhileNode, Do->getDoLoc());
Result Cond = Visit(Do->getCond());
WhileNode->SetRHS(exprToCond(getNodeAsRVal(Cond)));
LabelIdx EndLabel =
Builder->GetOrCreateMIRLabel("L_END" + std::to_string(++UnnamedCount));
LabelIdx ExitLabel =
Builder->GetOrCreateMIRLabel("L_EXIT" + std::to_string(++UnnamedCount));
EndLabels.push(LabelInfo(EndLabel));
ExitLabels.push(LabelInfo(ExitLabel));
const clang::Stmt *BodyStmt = Do->getBody();
Result BodyRes = Visit(BodyStmt);
if (llvm::isa<clang::CompoundStmt>(BodyStmt)) {
WhileNode->SetBody(static_cast<BlockNode *>(BodyRes.getNode()));
} else {
BlockNode *Block = Builder->GetCurrentFuncCodeMp()->New<BlockNode>();
addToBlock(Block, BodyRes);
WhileNode->SetBody(Block);
}
// Add an end label, if needed, to the end of the body
LabelInfo End = EndLabels.top();
if (End.Used) {
StmtNode *EndLabelStmt = Builder->CreateStmtLabel(End.Label);
EndLabelStmt->SetSrcPos(sourceLocation2Mpl(Do->getEndLoc()));
WhileNode->GetBody()->AddStatement(EndLabelStmt);
}
EndLabels.pop();
// The condition is called on every iteration of the loop, so if there are any
// statements that must run before the condition expression, insert them at
// the end of the loop.
Cond = Visit(Do->getCond());
getNodeAsRVal(Cond);
for (Result::iterator It = Cond.beginStmtsBefore();
It != Cond.endStmtsBefore(); ++It) {
WhileNode->GetBody()->AddStatement(*It);
}
// Add an exit label, if needed, after this loop
LabelInfo Exit = ExitLabels.top();
if (Exit.Used) {
StmtNode *ExitLabelStmt = Builder->CreateStmtLabel(Exit.Label);
ExitLabelStmt->SetSrcPos(sourceLocation2Mpl(Do->getEndLoc()));
Res.appendStmtAfter(ExitLabelStmt);
}
ExitLabels.pop();
return Res;
}
Result Clang2MapleVisitor::VisitForStmt(const clang::ForStmt *For) {
WhileStmtNode *WhileNode =
Builder->GetCurrentFuncCodeMp()->New<WhileStmtNode>(OP_while);
Result Res(WhileNode, For->getForLoc());
const clang::Stmt *InitStmt = For->getInit();
const clang::Expr *CondExpr = For->getCond();
const clang::Expr *IncExpr = For->getInc();
if (InitStmt) {
Result Init = Visit(InitStmt);
Res.appendStmts(Init);
if (!Init.mayDrop()) {
StmtNode *SNode = getNodeAsStmt(Init);
Res.appendStmtBefore(SNode);
}
}
Result Cond(CondExpr ? CondExpr->getBeginLoc() : For->getForLoc());
if (CondExpr) {
Cond = Visit(CondExpr);
WhileNode->SetRHS(exprToCond(getNodeAsRVal(Cond)));
Res.appendStmts(Cond);
} else {
// If condition is null, create a constant 1 for the condition.
WhileNode->SetRHS(Builder->CreateIntConst(1, PTY_i32));
}
LabelIdx EndLabel =
Builder->GetOrCreateMIRLabel("L_END" + std::to_string(++UnnamedCount));
LabelIdx ExitLabel =
Builder->GetOrCreateMIRLabel("L_EXIT" + std::to_string(++UnnamedCount));
EndLabels.push(LabelInfo(EndLabel));
ExitLabels.push(LabelInfo(ExitLabel));
const clang::Stmt *BodyStmt = For->getBody();
Result BodyRes = Visit(BodyStmt);
if (llvm::isa<clang::CompoundStmt>(BodyStmt)) {
WhileNode->SetBody(static_cast<BlockNode *>(BodyRes.getNode()));
} else {
BlockNode *Block = Builder->GetCurrentFuncCodeMp()->New<BlockNode>();
addToBlock(Block, BodyRes);
WhileNode->SetBody(Block);
}
// Add an end label, if needed, to the end of the body
LabelInfo End = EndLabels.top();
if (End.Used) {
StmtNode *EndLabelStmt = Builder->CreateStmtLabel(End.Label);
EndLabelStmt->SetSrcPos(sourceLocation2Mpl(For->getEndLoc()));
WhileNode->GetBody()->AddStatement(EndLabelStmt);
}
EndLabels.pop();
if (IncExpr) {
Result Inc = Visit(IncExpr);
addToBlock(WhileNode->GetBody(), Inc);
}
// The condition is called on every iteration of the loop, so if there are any
// statements that must run before the condition expression, insert them at
// the end of the loop.
if (CondExpr) {
Cond = Visit(CondExpr);
getNodeAsRVal(Cond);
for (Result::iterator It = Cond.beginStmtsBefore();
It != Cond.endStmtsBefore(); ++It) {
WhileNode->GetBody()->AddStatement(*It);
}
}
// Add an exit label, if needed, after this loop
LabelInfo Exit = ExitLabels.top();
if (Exit.Used) {
StmtNode *ExitLabelStmt = Builder->CreateStmtLabel(Exit.Label);
ExitLabelStmt->SetSrcPos(sourceLocation2Mpl(For->getEndLoc()));
Res.appendStmtAfter(ExitLabelStmt);
}
ExitLabels.pop();
return Res;
}
Result Clang2MapleVisitor::VisitIfStmt(const clang::IfStmt *If) {
Result Cond = Visit(If->getCond());
IfStmtNode *IfNode = Builder->CreateStmtIf(exprToCond(getNodeAsRVal(Cond)));
Result Res(IfNode, If->getBeginLoc());
Res.appendStmts(Cond);
const clang::Stmt *ThenStmt = If->getThen();
Result Then = Visit(ThenStmt);
if (llvm::isa<clang::CompoundStmt>(ThenStmt)) {
IfNode->SetThenPart(static_cast<BlockNode *>(Then.getNode()));
} else {
BlockNode *Block = Builder->GetCurrentFuncCodeMp()->New<BlockNode>();
addToBlock(Block, Then);
IfNode->SetThenPart(Block);
}
const clang::Stmt *ElseStmt = If->getElse();
if (ElseStmt) {
Result Else = Visit(ElseStmt);
if (llvm::isa<clang::CompoundStmt>(ElseStmt)) {
IfNode->SetElsePart(static_cast<BlockNode *>(Else.getNode()));
} else {
BlockNode *Block = Builder->GetCurrentFuncCodeMp()->New<BlockNode>();
addToBlock(Block, Else);
IfNode->SetElsePart(Block);
}
}
return Res;
}
Result Clang2MapleVisitor::VisitNullStmt(const clang::NullStmt *N) {
return Result(N->getBeginLoc());
}
Result Clang2MapleVisitor::VisitReturnStmt(const clang::ReturnStmt *Return) {
Result RetValRes(Return->getReturnLoc());
Result Res(Return->getReturnLoc());
BaseNode *RetVal = nullptr;
if (const clang::Expr *E = Return->getRetValue()) {
RetValRes = Visit(E);
Res.appendStmts(RetValRes);
if (E->getType()->isVoidType()) {
Res.appendStmtBefore(getNodeAsStmt(RetValRes));
} else {
RetVal = getNodeAsRVal(RetValRes);
Res.appendStmts(RetValRes);
}
} else if (Builder->GetCurrentFunction()->GetReturnType()->GetPrimType() !=
PTY_void) {
// Handle a return statement with no expression in a function that has a
// non-void return type.
RetVal = Builder->CreateConstval(
createZero(Builder->GetCurrentFunction()->GetReturnType()));
}
StmtNode *Ret = nullptr;
// If the address of a return structure has been passed as an implicit
// parameter, write the return value to it, otherwise, generate a return
// statement.
if (Builder->GetCurrentFunction()->IsFirstArgReturn()) {
FormalDef RetAddr = Builder->GetCurrentFunction()->GetFormalDefAt(0);
MIRType *RetTy =
GlobalTables::GetTypeTable().GetTypeFromTyIdx(RetAddr.formalTyIdx);
Ret = Builder->CreateStmtIassign(
*RetTy, 0, Builder->CreateExprDread(*RetTy, *RetAddr.formalSym),
RetVal);
} else {
Ret = Builder->CreateStmtReturn(RetVal);
}
Res.setNode(Ret);
return Res;
}
Result Clang2MapleVisitor::VisitWhileStmt(const clang::WhileStmt *While) {
WhileStmtNode *WhileNode =
Builder->GetCurrentFuncCodeMp()->New<WhileStmtNode>(OP_while);
Result Res(WhileNode, While->getWhileLoc());
Result Cond = Visit(While->getCond());
WhileNode->SetRHS(exprToCond(getNodeAsRVal(Cond)));
Res.appendStmts(Cond);
LabelIdx EndLabel =
Builder->GetOrCreateMIRLabel("L_END" + std::to_string(++UnnamedCount));
LabelIdx ExitLabel =
Builder->GetOrCreateMIRLabel("L_EXIT" + std::to_string(++UnnamedCount));
EndLabels.push(LabelInfo(EndLabel));
ExitLabels.push(LabelInfo(ExitLabel));
const clang::Stmt *BodyStmt = While->getBody();
Result BodyRes = Visit(BodyStmt);
if (llvm::isa<clang::CompoundStmt>(BodyStmt)) {
WhileNode->SetBody(static_cast<BlockNode *>(BodyRes.getNode()));
} else {
BlockNode *Block = Builder->GetCurrentFuncCodeMp()->New<BlockNode>();
addToBlock(Block, BodyRes);
WhileNode->SetBody(Block);
}
// Add an end label, if needed, to the end of the body
LabelInfo End = EndLabels.top();
if (End.Used) {
StmtNode *EndLabelStmt = Builder->CreateStmtLabel(End.Label);
EndLabelStmt->SetSrcPos(sourceLocation2Mpl(While->getEndLoc()));
WhileNode->GetBody()->AddStatement(EndLabelStmt);
}
EndLabels.pop();
// The condition is called on every iteration of the loop, so if there are any
// statements that must run before the condition expression, insert them at
// the end of the loop.
Cond = Visit(While->getCond());
getNodeAsRVal(Cond);
for (Result::iterator It = Cond.beginStmtsBefore();
It != Cond.endStmtsBefore(); ++It) {
WhileNode->GetBody()->AddStatement(*It);
}
// Add an exit label, if needed, after this loop
LabelInfo Exit = ExitLabels.top();
if (Exit.Used) {
StmtNode *ExitLabelStmt = Builder->CreateStmtLabel(Exit.Label);
ExitLabelStmt->SetSrcPos(sourceLocation2Mpl(While->getEndLoc()));
Res.appendStmtAfter(ExitLabelStmt);
}
ExitLabels.pop();
return Res;
}
Result Clang2MapleVisitor::VisitBreakStmt(const clang::BreakStmt *BS) {
ASSERT(ExitLabels.size() > 0, "'break' outside of known loop or switch");
LabelInfo &LI = ExitLabels.top();
LI.Used = true;
GotoNode *GoTo = Builder->CreateStmtGoto(OP_goto, LI.Label);
return Result(GoTo, BS->getBreakLoc());
}
Result Clang2MapleVisitor::VisitContinueStmt(const clang::ContinueStmt *CS) {
ASSERT(EndLabels.size() > 0, "'continue' outside of known loop");
LabelInfo &LI = EndLabels.top();
LI.Used = true;
GotoNode *GoTo = Builder->CreateStmtGoto(OP_goto, LI.Label);
return Result(GoTo, CS->getContinueLoc());
}
Result Clang2MapleVisitor::VisitLabelStmt(const clang::LabelStmt *LS) {
LabelIdx Label = Builder->GetOrCreateMIRLabel(LS->getName());
StmtNode *LabelStmt = Builder->CreateStmtLabel(Label);
LabelStmt->SetSrcPos(sourceLocation2Mpl(LS->getIdentLoc()));
Result SubExprRes = Visit(LS->getSubStmt());
SubExprRes.prependStmtBefore(LabelStmt);
return SubExprRes;
}
Result Clang2MapleVisitor::VisitGotoStmt(const clang::GotoStmt *Goto) {
LabelIdx Label =
Builder->GetOrCreateMIRLabel(Goto->getLabel()->getName().str());
StmtNode *GotoStmt = Builder->CreateStmtGoto(OP_goto, Label);
return Result(GotoStmt, Goto->getGotoLoc());
}
Result
Clang2MapleVisitor::VisitIndirectGotoStmt(const clang::IndirectGotoStmt *Goto) {
Result TargetRes = Visit(Goto->getTarget());
BaseNode *Target = getNodeAsRVal(TargetRes);
StmtNode *GotoStmt = Builder->GetCurrentFuncCodeMp()->New<UnaryStmtNode>(
OP_igoto, PointerPrimTy, Target);
Result Res(GotoStmt, Goto->getGotoLoc());
Res.appendStmts(TargetRes);
return Res;
}
Result Clang2MapleVisitor::VisitSwitchStmt(const clang::SwitchStmt *Switch) {
Result CondRes = Visit(Switch->getCond());
CaseVector *Cases = Builder->GetCurrentFuncCodeMp()->New<CaseVector>(
Builder->GetCurrentFuncCodeMpAllocator()->Adapter());
SwitchCases.push(Cases);
LabelIdx DefaultLabel = Builder->GetOrCreateMIRLabel(
"L_DEFAULT" + std::to_string(++UnnamedCount));
LabelIdx BreakLabel =
Builder->GetOrCreateMIRLabel("L_BREAK" + std::to_string(++UnnamedCount));
EndLabels.push(LabelInfo(DefaultLabel));
ExitLabels.push(LabelInfo(BreakLabel));
const clang::Stmt *BodyStmt = Switch->getBody();
Result BodyRes = Visit(BodyStmt);
// Generate a temporary for the switch condition
MIRSymbol *Temp = Builder->GetOrCreateLocalDecl(
"_switch." + std::to_string(Switch->getID(*Context)),
*CondRes.getValueTy());
StmtNode *TempAssign =
Builder->CreateStmtDassign(*Temp, 0, getNodeAsRVal(CondRes));
TempAssign->SetSrcPos(sourceLocation2Mpl(CondRes.getLoc()));
BaseNode *ReadCond = Builder->CreateExprDread(*CondRes.getValueTy(), *Temp);
SwitchNode *SwitchStmt =
Builder->CreateStmtSwitch(ReadCond, DefaultLabel, *Cases);
Result Res(SwitchStmt, Switch->getSwitchLoc());
// Add statements that need to run before the switch, from the condition.
for (Result::iterator It = CondRes.beginStmtsBefore();
It != CondRes.endStmtsBefore(); ++It) {
Res.appendStmtBefore(*It);
}
Res.appendStmtBefore(TempAssign);
// Add the body after the switch.
if (llvm::isa<clang::CompoundStmt>(BodyStmt)) {
BlockNode *BodyBlock = static_cast<BlockNode *>(BodyRes.getNode());
for (auto &Stmt : BodyBlock->GetStmtNodes()) {
Res.appendStmtAfter(&Stmt);
}
} else {
StmtNode *SNode = getNodeAsStmt(BodyRes);
Res.appendStmtAfter(SNode);
}
// If there was no default case, add the label.
LabelInfo &DefaultLI = EndLabels.top();
if (!DefaultLI.Used) {
StmtNode *DefaultStmt = Builder->CreateStmtLabel(DefaultLI.Label);
DefaultStmt->SetSrcPos(sourceLocation2Mpl(Switch->getSwitchLoc()));
Res.appendStmtAfter(DefaultStmt);
}
// If there were any breaks in the body, add the label for the exit.
LabelInfo &ExitLI = ExitLabels.top();
if (ExitLI.Used) {
StmtNode *ExitLabelStmt = Builder->CreateStmtLabel(ExitLI.Label);
ExitLabelStmt->SetSrcPos(sourceLocation2Mpl(Switch->getEndLoc()));
Res.appendStmtAfter(ExitLabelStmt);
}
SwitchCases.pop();
EndLabels.pop();
ExitLabels.pop();
return Res;
}
Result Clang2MapleVisitor::VisitCaseStmt(const clang::CaseStmt *CS) {
LabelIdx Label =
Builder->GetOrCreateMIRLabel("L_CASE" + std::to_string(++UnnamedCount));
StmtNode *LabelStmt = Builder->CreateStmtLabel(Label);
LabelStmt->SetSrcPos(sourceLocation2Mpl(CS->getCaseLoc()));
clang::Expr::EvalResult Constant;
bool IsConstant = CS->getLHS()->EvaluateAsConstantExpr(
Constant, clang::Expr::EvaluateForCodeGen, *Context);
ASSERT(IsConstant, "case statement expression is not constant");
if (!Constant.Val.isInt()) {
LogInfo::MapleLogger() << "Error: Constant.Val in case statement is "
<< Constant.Val.getKind() << "\n";
Constant.Val.dump();
}
llvm::APSInt Value = Constant.Val.getInt();
ASSERT(SwitchCases.size() > 0, "'case' outside of known switch");
CaseVector *Cases = SwitchCases.top();
Cases->push_back(CasePair(Value.getExtValue(), Label));
Result Body = Visit(CS->getSubStmt());
Body.prependStmtBefore(LabelStmt);
return Body;
}
Result Clang2MapleVisitor::VisitDefaultStmt(const clang::DefaultStmt *DS) {
ASSERT(EndLabels.size() > 0, "'default' outside of known switch");
LabelInfo &LI = EndLabels.top();
StmtNode *DefaultStmt = Builder->CreateStmtLabel(LI.Label);
DefaultStmt->SetSrcPos(sourceLocation2Mpl(DS->getDefaultLoc()));
LI.Used = true;
Result Body = Visit(DS->getSubStmt());
Body.prependStmtBefore(DefaultStmt);
return Body;
}
//
// Visit Expressions
//
Result Clang2MapleVisitor::VisitAddrLabelExpr(const clang::AddrLabelExpr *ALE) {
LabelIdx Label =
Builder->GetOrCreateMIRLabel(ALE->getLabel()->getName().str());
AddroflabelNode *AOL =
Builder->GetCurrentFuncCodeMp()->New<AddroflabelNode>(Label);
AOL->SetPrimType(PointerPrimTy);
return Result(AOL, ALE->getAmpAmpLoc(), type2Mpl(ALE->getType()));
}
Result Clang2MapleVisitor::VisitArraySubscriptExpr(
const clang::ArraySubscriptExpr *ASE) {
MIRType *Ty = type2Mpl(ASE->getType());
Result BaseRes = Visit(ASE->getBase());
Result IdxRes = Visit(ASE->getIdx());
// If this is a multi-dimensional array, append to the existing array node
BaseNode *ArrBase = BaseRes.getNode();
ArrayNode *Array;
// If this is a multi-dimensional array subscript (ex. x[3][4]), append to the
// existing array node.
if (ArrBase && ArrBase->GetOpCode() == OP_array && BaseRes.getField() == 0) {
Array = static_cast<ArrayNode *>(ArrBase);
MapleVector<BaseNode *> &Opnds = Array->GetNopnd();
Opnds.push_back(getNodeAsRVal(IdxRes));
Array->SetNumOpnds(Opnds.size());
} else {
// Get the base array type from the base expression, ignoring the implicit
// array-to-pointer decay cast
MIRType *ArrayTy = type2Mpl(ASE->getBase()->IgnoreImpCasts()->getType());
if (ArrayTy->GetKind() == kTypePointer) {
MIRPtrType *PointerTy = static_cast<MIRPtrType *>(ArrayTy);
MIRType *PointeeTy = PointerTy->GetPointedType();
ArrayTy =
GlobalTables::GetTypeTable().GetOrCreateArrayType(*PointeeTy, 1);
}
// If this is an access of a 0-size array, change the type to be a 1-size
// array.
if (ArrayTy->GetKind() == kTypeArray) {
MIRArrayType *ArrTy = static_cast<MIRArrayType *>(ArrayTy);
if (ArrTy->GetSizeArrayItem(0) == 0) {
ArrayTy = GlobalTables::GetTypeTable().GetOrCreateArrayType(
*ArrTy->GetElemType(), 1);
}
}
Array = Builder->CreateExprArray(*ArrayTy, getNodeAsRVal(BaseRes),
getNodeAsRVal(IdxRes));
Array->SetBoundsCheck(false);
Array->SetPrimType(PointerPrimTy);
}
Result Res(Array, type2Mpl(ASE->getBase()->getType()), Ty,
ASE->getBeginLoc());
Res.appendStmts(BaseRes);
Res.appendStmts(IdxRes);
return Res;
}
Result
Clang2MapleVisitor::VisitBinaryOperator(const clang::BinaryOperator *BO) {
Result Lhs = Visit(BO->getLHS());
Result Rhs = Visit(BO->getRHS());
MIRType *Ty = type2Mpl(BO->getType());
StmtNode *Assign = nullptr;
// Assignments need to be handled differently from the other operators
if (BO->isAssignmentOp()) {
Result Res(BO->getExprLoc());
BaseNode *RhsNode = getNodeAsRVal(Rhs);
bool CompoundAssign = false;
// For compound assignments, convert the RHS to LHS op RHS
if (auto CAO = llvm::dyn_cast<clang::CompoundAssignOperator>(BO)) {
CompoundAssign = true;
bool isSigned = BO->getType()->isSignedIntegerType();
Opcode Op = BinOpcode2Mpl(BO->getOpcode(), isSigned);
ASSERT(Op != OP_undef, "Unhandled opcode in binary operator");
MIRType *ResultTy = type2Mpl(CAO->getComputationResultType());
MIRType *LhsTy = type2Mpl(CAO->getComputationLHSType());
BaseNode *LhsOp = getNodeAsRVal(Lhs);
if (Lhs.getValueTy() != LhsTy) {
LhsOp = Builder->CreateExprTypeCvt(OP_cvt, *LhsTy, *Lhs.getValueTy(),
LhsOp);
}
// If this is addition or subtraction of a pointer and an integer, the
// integer must be scaled to the size of the pointed-to type.
if (Op == OP_add || Op == OP_sub) {
if (isPointerType(LhsTy) && !isPointerType(Rhs.getValueTy())) {
size_t Scale =
static_cast<MIRPtrType *>(LhsTy)->GetPointedType()->GetSize();
if (Scale > 1) { // Skip multiplication for 1 (char) and 0 (void)
if (RhsNode->GetOpCode() == OP_constval) {
ConstvalNode *RhsConst = static_cast<ConstvalNode *>(RhsNode);
ASSERT(RhsConst->GetConstVal()->GetKind() == kConstInt,
"expected int const");
MIRIntConst *IntConst =
static_cast<MIRIntConst *>(RhsConst->GetConstVal());
int64_t Val = IntConst->GetValue();
RhsNode = Builder->CreateIntConst(Val * Scale, PointerPrimTy);
} else {
ConstvalNode *Const =
Builder->CreateIntConst(Scale, PointerPrimTy);
RhsNode = Builder->CreateExprBinary(OP_mul, *IntPointerTy,
RhsNode, Const);
}
}
}
}
RhsNode = Builder->CreateExprBinary(Op, *ResultTy, LhsOp, RhsNode);
if (ResultTy != Ty) {
RhsNode = Builder->CreateExprTypeCvt(OP_cvt, *Ty, *ResultTy, RhsNode);
}
}
BaseNode *N;
if (Lhs.isDeref()) {
Assign = Builder->CreateStmtIassign(*Lhs.getAddrTy(), Lhs.getField(),
Lhs.getAddr(), RhsNode);
if (CompoundAssign) {
N = Builder->CreateExprIread(*Lhs.getValueTy(), *Lhs.getAddrTy(),
Lhs.getField(), Lhs.getAddr());
}
} else if (Lhs.isSym()) {
Assign =
Builder->CreateStmtDassign(*Lhs.getSym(), Lhs.getField(), RhsNode);
if (CompoundAssign) {
N = Builder->CreateExprDread(*Lhs.getValueTy(), Lhs.getField(),
*Lhs.getSym());
}
} else {
BO->getLHS()->dump();
ASSERT(false, "Error: LHS of assign is neither deref or symbol");
}
Res.appendStmts(Rhs);
Res.appendStmts(Lhs);
if (CompoundAssign) {
Assign->SetSrcPos(sourceLocation2Mpl(BO->getExprLoc()));
Res.appendStmtBefore(Assign);
Res.setNode(N, Lhs.getValueTy(), true);
} else {
Res.setNode(Assign, Ty);
}
return Res;
}
// Comma operator is also unique
if (BO->getOpcode() == clang::BO_Comma) {
Result Res(BO->getRHS()->getBeginLoc());
appendResultBefore(Res, Lhs);
Res.appendStmts(Rhs);
Res.setResult(Rhs);
return Res;
}
BaseNode *RhsNode = getNodeAsRVal(Rhs);
BaseNode *LhsNode = getNodeAsRVal(Lhs);
BaseNode *BinNode;
bool isSigned = BO->getType()->isSignedIntegerType();
Opcode Op = BinOpcode2Mpl(BO->getOpcode(), isSigned);
ASSERT(Op != OP_undef, "Unhandled opcode in binary operator");
if (Op == OP_lior || Op == OP_land) {
// Handle C's short-circuiting rules:
// x || y;
// becomes:
// _shortcircuit.0 = x;
// if (_shortcircuit.0) goto L0;
// _shortcircuit.0 = y;
// L0: _shortcircuit.0
Result Res(BO->getExprLoc());
MIRType *IntTy =
GlobalTables::GetTypeTable().GetTypeFromTyIdx(TyIdx(PTY_i32));
// The label should be recreated if this node is visited multiple times, so
// use an iterative name.
LabelIdx LabelID = Builder->GetOrCreateMIRLabel(
"Lshortcircuit." + std::to_string(++UnnamedCount));
// The temporary variable should be reused if this node is visited multiple
// times, so use a stable name.
MIRSymbol *Temp = Builder->GetOrCreateLocalDecl(
"_shortcircuit." + std::to_string(BO->getID(*Context)), *IntTy);
Res.appendStmts(Lhs);
StmtNode *TempAssign =
Builder->CreateStmtDassign(*Temp, 0, exprToCond(LhsNode));
TempAssign->SetSrcPos(sourceLocation2Mpl(Lhs.getLoc()));
Res.appendStmtBefore(TempAssign);
CondGotoNode *Branch = Builder->CreateStmtCondGoto(
Builder->CreateExprDread(*IntTy, *Temp),
Op == OP_lior ? OP_brtrue : OP_brfalse, LabelID);
Branch->SetSrcPos(sourceLocation2Mpl(BO->getOperatorLoc()));
Res.appendStmtBefore(Branch);
Res.appendStmts(Rhs);
TempAssign = Builder->CreateStmtDassign(*Temp, 0, exprToCond(RhsNode));
TempAssign->SetSrcPos(sourceLocation2Mpl(Rhs.getLoc()));
Res.appendStmtBefore(TempAssign);
StmtNode *LabelStmt = Builder->CreateStmtLabel(LabelID);
LabelStmt->SetSrcPos(sourceLocation2Mpl(BO->getOperatorLoc()));
Res.appendStmtBefore(LabelStmt);
Res.setSym(Temp, IntTy, true);
return Res;
} else if (kOpcodeInfo.IsCompare(Op)) {
// Compare operators need two types
MIRType *OpndTy = type2Mpl(BO->getLHS()->getType());
BinNode = Builder->CreateExprCompare(Op, *Ty, *OpndTy, LhsNode, RhsNode);
} else {
MIRType *LhsTy = Lhs.getValueTy();
MIRType *RhsTy = Rhs.getValueTy();
// If this is addition or subtraction of a pointer and an integer, the
// integer must be scaled to the size of the pointed-to type.
if (Op == OP_add || Op == OP_sub) {
if (!isPointerType(LhsTy) && isPointerType(RhsTy)) {
size_t Scale =
static_cast<MIRPtrType *>(RhsTy)->GetPointedType()->GetSize();
if (Scale > 1) { // Skip multiplication for 1 (char) and 0 (void)
if (LhsNode->GetOpCode() == OP_constval) {
ConstvalNode *LhsConst = static_cast<ConstvalNode *>(LhsNode);
ASSERT(LhsConst->GetConstVal()->GetKind() == kConstInt,
"expected int const");
MIRIntConst *IntConst =
static_cast<MIRIntConst *>(LhsConst->GetConstVal());
int64_t Val = IntConst->GetValue();
LhsNode = Builder->CreateIntConst(Val * Scale, PointerPrimTy);
} else {
ConstvalNode *Const = Builder->CreateIntConst(Scale, PointerPrimTy);
LhsNode = Builder->CreateExprBinary(OP_mul, *IntPointerTy, LhsNode,
Const);
}
}
} else if (isPointerType(LhsTy) && !isPointerType(RhsTy)) {
size_t Scale =
static_cast<MIRPtrType *>(LhsTy)->GetPointedType()->GetSize();
if (Scale > 1) { // Skip multiplication for 1 (char) and 0 (void)
if (RhsNode->GetOpCode() == OP_constval) {
ConstvalNode *RhsConst = static_cast<ConstvalNode *>(RhsNode);
ASSERT(RhsConst->GetConstVal()->GetKind() == kConstInt,
"expected int const");
MIRIntConst *IntConst =
static_cast<MIRIntConst *>(RhsConst->GetConstVal());
int64_t Val = IntConst->GetValue();
RhsNode = Builder->CreateIntConst(Val * Scale, PointerPrimTy);
} else {
ConstvalNode *Const = Builder->CreateIntConst(Scale, PointerPrimTy);
RhsNode = Builder->CreateExprBinary(OP_mul, *IntPointerTy, RhsNode,
Const);
}
}
}
}
BinNode = Builder->CreateExprBinary(Op, *Ty, LhsNode, RhsNode);
// For the difference of two pointers, the result needs to be scaled by the
// size of the pointed-to object.
if (Op == OP_sub && isPointerType(LhsTy) && isPointerType(RhsTy)) {
size_t Scale =
static_cast<MIRPtrType *>(LhsTy)->GetPointedType()->GetSize();
if (Scale > 1) { // Skip multiplication for 1 (char) and 0 (void)
ConstvalNode *Const = Builder->CreateIntConst(Scale, PointerPrimTy);
BinNode = Builder->CreateExprBinary(OP_div, *Ty, BinNode, Const);
}
}
}
Result BinRes(BinNode, BO->getExprLoc(), Ty);
BinRes.appendStmts(Rhs);
BinRes.appendStmts(Lhs);
return BinRes;
}
Result Clang2MapleVisitor::VisitBinaryConditionalOperator(
const clang::BinaryConditionalOperator *BCO) {
Result CondRes = Visit(BCO->getCond());
Result FalseRes = Visit(BCO->getFalseExpr());
MIRType *Ty = type2Mpl(BCO->getType());
// In the simple case, both true and false are just one expression
if (Ty->GetPrimType() != PTY_void && CondRes.isSimple() &&
FalseRes.isSimple()) {
Result Res(Builder->CreateExprTernary(
OP_select, *Ty, getNodeAsRVal(CondRes),
getNodeAsRVal(CondRes), getNodeAsRVal(FalseRes)),
BCO->getBeginLoc(), Ty);
Res.appendStmts(CondRes);
return Res;
}
// If not, then expand to an if-then-else
MIRSymbol *Temp = nullptr;
if (Ty->GetPrimType() != PTY_void) {
Temp =
Builder->CreateLocalDecl("cond." + std::to_string(++UnnamedCount), *Ty);
}
Result Res(Temp, Ty, BCO->getBeginLoc());
IfStmtNode *IfNode =
Builder->CreateStmtIf(exprToNotCond(getNodeAsRVal(CondRes)));
Res.appendStmts(CondRes);
BlockNode *Block = Builder->GetCurrentFuncCodeMp()->New<BlockNode>();
StmtNode *FalsePart;
if (Temp) {
FalsePart = Builder->CreateStmtDassign(*Temp, 0, getNodeAsRVal(FalseRes));
} else {
FalsePart = getNodeAsStmt(FalseRes);
}
for (Result::iterator It = FalseRes.beginStmtsBefore();
It != FalseRes.endStmtsBefore(); ++It) {
Block->AddStatement(*It);
}
addStmtToBlock(Block, FalsePart);
for (Result::iterator It = FalseRes.beginStmtsAfter();
It != FalseRes.endStmtsAfter(); ++It) {
Block->AddStatement(*It);
}
IfNode->SetThenPart(Block);
IfNode->SetSrcPos(sourceLocation2Mpl(BCO->getBeginLoc()));
Res.appendStmtBefore(IfNode);
return Res;
}
Result Clang2MapleVisitor::VisitCallExpr(const clang::CallExpr *CE) {
MapleVector<BaseNode *> Args(
Builder->GetCurrentFuncCodeMpAllocator()->Adapter());
Result Res(CE->getBeginLoc());
unsigned NumArgs = CE->getNumArgs();
for (unsigned i = 0; i < NumArgs; ++i) {
Result ArgRes = Visit(CE->getArg(i));
Args.push_back(getNodeAsRVal(ArgRes));
Res.appendStmts(ArgRes);
}
const clang::FunctionDecl *CalleeDecl = CE->getDirectCallee();
MIRType *Ty = type2Mpl(CE->getType());
// Indirect call
if (!CalleeDecl) {
Result CalleeRes = Visit(CE->getCallee());
Res.appendStmts(CalleeRes);
Args.insert(Args.begin(), getNodeAsRVal(CalleeRes));
IcallNode *ICall = Builder->CreateStmtIcall(Args);
Res.setNode(ICall, Ty);
return Res;
} else {
BaseNode *Call;
// Special cases for some builtins
if (CalleeDecl->getName() == "__builtin_va_start") {
// The address of the ap_list parameter needs to be passed
Args[0] = getAddrOfNode(Args[0]);
Call = Builder->CreateStmtIntrinsicCall(INTRN_C_va_start, Args);
} else if (CalleeDecl->getName() == "__builtin_va_copy") {
ASSERT(Args.size() == 2, "ap_copy expects 2 arguments");
// The address of the ap_list parameters needs to be passed
Args[0] = getAddrOfNode(Args[0]);
Args[1] = getAddrOfNode(Args[1]);
// Add the size of the ap_list structure as the size to memcpy.
clang::TypedefDecl *VaListTypeDef = Context->getBuiltinVaListDecl();
MIRType *APListTy = type2Mpl(VaListTypeDef->getUnderlyingType());
Args.push_back(Builder->GetConstInt(APListTy->GetSize()));
Call = Builder->CreateStmtIntrinsicCall(INTRN_C_memcpy, Args);
} else if (CalleeDecl->getName() == "__builtin_va_end") {
// Nothing needs to be done for this function
return Res;
// } else if (CalleeDecl->getName() == "__builtin_memcmp") {
// Call = Builder->CreateStmtIntrinsicCall(INTRN_C_memcmp, Args);
// } else if (CalleeDecl->getName() == "__builtin_memcpy") {
// Call = Builder->CreateStmtIntrinsicCall(INTRN_C_memcpy, Args);
// } else if (CalleeDecl->getName() == "__builtin_memset") {
// Call = Builder->CreateStmtIntrinsicCall(INTRN_C_memset, Args);
// } else if (CalleeDecl->getName() == "__builtin_ffs") {
// Call = Builder->CreateStmtIntrinsicCall(INTRN_C_ffs, Args);
} else if (CalleeDecl->getName() == "__builtin_ctz") {
if (Ty->GetSize() == 4) {
Call = Builder->CreateExprIntrinsicop(INTRN_C_ctz32, OP_intrinsicop,
*Ty, Args);
} else {
Call = Builder->CreateExprIntrinsicop(INTRN_C_ctz64, OP_intrinsicop,
*Ty, Args);
}
} else if (CalleeDecl->getName() == "__builtin_clz") {
if (Ty->GetSize() == 4) {
Call = Builder->CreateExprIntrinsicop(INTRN_C_clz32, OP_intrinsicop,
*Ty, Args);
} else {
Call = Builder->CreateExprIntrinsicop(INTRN_C_clz64, OP_intrinsicop,
*Ty, Args);
}
} else if (CalleeDecl->getName() == "alloca" ||
CalleeDecl->getName() == "__builtin_alloca") {
Call = Builder->CreateExprUnary(OP_alloca, *Ty, Args[0]);
Call->SetPrimType(PointerPrimTy);
} else if (CalleeDecl->getName() == "__builtin_constant_p") {
int Val = CE->getArg(0)->isConstantInitializer(*Context, false) ? 1 : 0;
Call = Builder->CreateIntConst(Val, Ty->GetPrimType());
} else if (CalleeDecl->getName() == "__builtin_classify_type") {
// Let Clang figure out the type classification
clang::Expr::EvalResult R;
bool Success = CE->EvaluateAsInt(R, *Context);
ASSERT(Success, "Failed to evaluate __builtin_classify_type");
llvm::APSInt Val = R.Val.getInt();
Call = Builder->CreateIntConst(Val.getExtValue(), Ty->GetPrimType());
} else if (CalleeDecl->getName() == "__builtin_expect") {
ASSERT(Args.size() == 2, "__builtin_expect requires two arguments");
// Arg 0 is the expression and arg 1 is the expected value.
Call = Args[0];
// TODO: Currently the expected value is just executed, but we should do
// something with it to improve performance.
StmtNode *SNode;
if (kOpcodeInfo.IsStmt(Args[1]->op)) {
SNode = static_cast<StmtNode *>(Args[1]);
} else {
// If the node is an expression, not a statement, wrap it in an eval
SNode = Builder->CreateStmtUnary(OP_eval, Args[1]);
}
Res.appendStmtBefore(SNode);
} else if (CalleeDecl->getName() == "__builtin_signbit") {
MIRFunction *Callee =
Builder->GetOrCreateFunction("__signbit", Ty->GetTypeIndex());
Call = Builder->CreateStmtCall(Callee->GetPuidx(), Args);
} else if (CalleeDecl->getName() == "__builtin_prefetch") {
// TODO: Do something useful here.
return Res;
} else if (CalleeDecl->getName() == "__builtin_isinf_sign") {
ASSERT(Args.size() == 1, "Incorrect arguments to isinf");
if (Args[0]->GetPrimType() == PTY_f64) {
Call = Builder->CreateStmtCall("__isinf", Args);
} else if (Args[0]->GetPrimType() == PTY_f32) {
Call = Builder->CreateStmtCall("__isinff", Args);
} else {
ASSERT(false, "Unsupported type passed to isinf");
}
} else if (CalleeDecl->getName().startswith("__builtin_")) {
MIRFunction *Callee = Builder->GetOrCreateFunction(
CalleeDecl->getName().substr(10).str(), Ty->GetTypeIndex());
Call = Builder->CreateStmtCall(Callee->GetPuidx(), Args);
} else {
MIRSymbol *CalleeSym = decl2Mpl(CalleeDecl);
MIRFunction *Callee = CalleeSym->GetFunction();
Call = Builder->CreateStmtCall(Callee->GetPuidx(), Args);
}
Res.setNode(Call, Ty);
return Res;
}
}
Result Clang2MapleVisitor::VisitCastExpr(const clang::CastExpr *CE) {
Result SubExprRes = Visit(CE->getSubExpr());
MIRType *FromTy = type2Mpl(CE->getSubExpr()->getType());
MIRType *ToTy = type2Mpl(CE->getType());
Result Res(CE->getExprLoc());
switch (CE->getCastKind()) {
case clang::CK_BitCast: {
BaseNode *SubExpr = getNodeAsRVal(SubExprRes);
if (ToTy->GetKind() == kTypePointer) {
Res.setNode(SubExpr, ToTy);
} else {
Res.setNode(Builder->CreateExprRetype(*ToTy, *FromTy, SubExpr), ToTy);
}
} break;
// This must be handled by the parent node
case clang::CK_LValueToRValue:
// Nothing needs to be passed down into the IR for these
case clang::CK_NoOp:
case clang::CK_ToVoid:
return SubExprRes;
case clang::CK_ArrayToPointerDecay: {
if (SubExprRes.isSym()) {
BaseNode *AddrOf = Builder->CreateExprAddrof(SubExprRes.getField(),
*SubExprRes.getSym());
AddrOf->SetPrimType(PointerPrimTy);
Result NodeRes(AddrOf, ToTy, FromTy, CE->getExprLoc());
NodeRes.appendStmts(SubExprRes);
return NodeRes;
}
if (SubExprRes.getField()) {
Result FieldRes(Builder->CreateExprIaddrof(*ToTy, *SubExprRes.getAddrTy(),
SubExprRes.getField(),
SubExprRes.getNode()),
ToTy, FromTy, CE->getExprLoc());
FieldRes.appendStmts(SubExprRes);
return FieldRes;
}
Result Res(getNodeAsRVal(SubExprRes), ToTy, FromTy, CE->getExprLoc());
Res.appendStmts(SubExprRes);
return Res;
}
case clang::CK_NullToPointer:
case clang::CK_IntegralToPointer: {
// Change the type of the const
if (BaseNode *N = SubExprRes.getNode()) {
if (N->GetOpCode() == OP_constval) {
ConstvalNode *ConstNode = static_cast<ConstvalNode *>(N);
MIRConst *Const = ConstNode->GetConstVal();
ASSERT(Const->GetKind() == kConstInt, "Expected constant int in cast");
MIRIntConst *IntConst = static_cast<MIRIntConst *>(Const);
ConstNode->SetConstVal(
GlobalTables::GetIntConstTable().GetOrCreateIntConst(
IntConst->GetValue(), *IntPointerTy));
}
N->SetPrimType(PointerPrimTy);
}
SubExprRes.setValueTy(ToTy);
return SubExprRes;
}
case clang::CK_FunctionToPointerDecay:
// This is just a type change
SubExprRes.setValueTy(ToTy);
return SubExprRes;
case clang::CK_IntegralCast:
Res.setNode(Builder->CreateExprTypeCvt(OP_cvt, *ToTy, *FromTy,
getNodeAsRVal(SubExprRes)),
ToTy);
break;
case clang::CK_IntegralToBoolean:
case clang::CK_PointerToBoolean:
case clang::CK_FloatingToBoolean:
Res.setNode(exprToCond(getNodeAsRVal(SubExprRes)), ToTy);
break;
case clang::CK_PointerToIntegral:
Res.setNode(getNodeAsRVal(SubExprRes), ToTy);
break;
case clang::CK_IntegralToFloating:
case clang::CK_FloatingCast:
// Because we treat `long double` as `double`, this may be a cast to/from
// the same type. If so, do not generate a convert node.
if (ToTy == FromTy) {
return SubExprRes;
}
Res.setNode(Builder->CreateExprTypeCvt(OP_cvt, *ToTy, *FromTy,
getNodeAsRVal(SubExprRes)),
ToTy);
break;
case clang::CK_FloatingToIntegral: {
BaseNode *SubExpr = getNodeAsRVal(SubExprRes);
if (ToTy->GetSize() < 4) {
bool IsUnsigned = PrimitiveType(ToTy->GetPrimType()).IsUnsigned();
TypeCvtNode *Cvt =
Builder->CreateExprTypeCvt(OP_cvt, IsUnsigned ? PTY_u32 : PTY_i32,
FromTy->GetPrimType(), *SubExpr);
Res.setNode(Builder->CreateExprExtractbits(IsUnsigned ? OP_zext : OP_sext,
*ToTy, 0, 16, Cvt),
ToTy);
} else {
Res.setNode(Builder->CreateExprTypeCvt(OP_cvt, *ToTy, *FromTy, SubExpr),
ToTy);
}
} break;
default:
LogInfo::MapleLogger() << "Warning: Unhandled cast kind: "
<< CE->getCastKindName() << "\n";
return SubExprRes;
}
Res.appendStmts(SubExprRes);
return Res;
}
Result
Clang2MapleVisitor::VisitCharacterLiteral(const clang::CharacterLiteral *CL) {
MIRType *Ty = type2Mpl(CL->getType());
ConstvalNode *Const =
Builder->CreateIntConst(CL->getValue(), Ty->GetPrimType());
return Result(Const, CL->getLocation(), Ty);
}
Result Clang2MapleVisitor::VisitChooseExpr(const clang::ChooseExpr *CE) {
return Visit(CE->getChosenSubExpr());
}
Result Clang2MapleVisitor::VisitCompoundLiteralExpr(
const clang::CompoundLiteralExpr *CLE) {
MIRType *Ty = type2Mpl(CLE->getType());
ASSERT(Ty->IsStructType() || Ty->GetKind() == kTypeArray,
"Unexpected type of CompoundLiteralExpr (not struct or array)");
// Create a temporary value for this structure and initialize it using this
// literal expression
if (Builder->GetCurrentFunction()) {
Result InitRes = Visit(CLE->getInitializer());
MIRSymbol *Temp = Builder->GetOrCreateLocalDecl(
"cle." + std::to_string(++UnnamedCount), *Ty);
Result Res(Temp, Ty, CLE->getBeginLoc());
Res.appendStmts(InitRes);
BaseNode *InitNode = InitRes.getNode();
if (InitNode) {
if (Ty->IsStructType()) {
MIRStructType *StructTy = static_cast<MIRStructType *>(Ty);
assignStruct(Res, Temp, nullptr, StructTy, InitNode);
} else { // array
MIRArrayType *ArrayTy = static_cast<MIRArrayType *>(Ty);
BaseNode *Base = Builder->CreateExprAddrof(0, *Temp);
Base->SetPrimType(PointerPrimTy);
assignArray(Res, Base, ArrayTy, InitNode);
}
}
return Res;
} else {
MIRConst *Init = getInitializer(Ty, CLE->getInitializer());
MIRSymbol *Temp =
Builder->CreateGlobalDecl("cle." + std::to_string(++UnnamedCount), *Ty);
Temp->SetKonst(Init);
return Result(Temp, Ty, CLE->getBeginLoc());
}
}
Result Clang2MapleVisitor::VisitConditionalOperator(
const clang::ConditionalOperator *CO) {
Result CondRes = Visit(CO->getCond());
Result TrueRes = Visit(CO->getTrueExpr());
Result FalseRes = Visit(CO->getFalseExpr());
MIRType *Ty = type2Mpl(CO->getType());
// In the simple case, both true and false are just one expression
if (Ty->GetPrimType() != PTY_void && TrueRes.isSimple() &&
FalseRes.isSimple()) {
Result Res(Builder->CreateExprTernary(
OP_select, *Ty, getNodeAsRVal(CondRes),
getNodeAsRVal(TrueRes), getNodeAsRVal(FalseRes)),
CO->getBeginLoc(), Ty);
Res.appendStmts(CondRes);
return Res;
}
// If not, then expand to an if-then-else
MIRSymbol *Temp = nullptr;
if (Ty->GetPrimType() != PTY_void) {
Temp =
Builder->CreateLocalDecl("cond." + std::to_string(++UnnamedCount), *Ty);
}
Result Res(Temp, Ty, CO->getBeginLoc());
IfStmtNode *IfNode =
Builder->CreateStmtIf(exprToCond(getNodeAsRVal(CondRes)));
Res.appendStmts(CondRes);
BlockNode *Block = Builder->GetCurrentFuncCodeMp()->New<BlockNode>();
StmtNode *TruePart;
if (Temp) {
TruePart = Builder->CreateStmtDassign(*Temp, 0, getNodeAsRVal(TrueRes));
} else {
TruePart = getNodeAsStmt(TrueRes);
}
for (Result::iterator It = TrueRes.beginStmtsBefore();
It != TrueRes.endStmtsBefore(); ++It) {
Block->AddStatement(*It);
}
addStmtToBlock(Block, TruePart);
for (Result::iterator It = TrueRes.beginStmtsAfter();
It != TrueRes.endStmtsAfter(); ++It) {
Block->AddStatement(*It);
}
IfNode->SetThenPart(Block);
Block = Builder->GetCurrentFuncCodeMp()->New<BlockNode>();
StmtNode *FalsePart;
if (Temp) {
FalsePart = Builder->CreateStmtDassign(*Temp, 0, getNodeAsRVal(FalseRes));
} else {
FalsePart = getNodeAsStmt(FalseRes);
}
for (Result::iterator It = FalseRes.beginStmtsBefore();
It != FalseRes.endStmtsBefore(); ++It) {
Block->AddStatement(*It);
}
addStmtToBlock(Block, FalsePart);
for (Result::iterator It = FalseRes.beginStmtsAfter();
It != FalseRes.endStmtsAfter(); ++It) {
Block->AddStatement(*It);
}
IfNode->SetElsePart(Block);
IfNode->SetSrcPos(sourceLocation2Mpl(CO->getBeginLoc()));
Res.appendStmtBefore(IfNode);
return Res;
}
Result Clang2MapleVisitor::VisitConstantExpr(const clang::ConstantExpr *CE) {
// This is just a wrapper expression
return Visit(CE->getSubExpr());
}
Result Clang2MapleVisitor::VisitDeclRefExpr(const clang::DeclRefExpr *DRE) {
MIRType *Ty = type2Mpl(DRE->getType());
const clang::ValueDecl *D = DRE->getDecl();
// We do not actually create symbols for enums, just extract the constant
if (auto EnumConst = llvm::dyn_cast<clang::EnumConstantDecl>(D)) {
const llvm::APSInt Value = EnumConst->getInitVal();
ConstvalNode *ConstNode =
Builder->CreateIntConst(Value.getExtValue(), Ty->GetPrimType());
return Result(ConstNode, DRE->getLocation(), Ty);
}
MIRSymbol *Sym = decl2Mpl(D);
return Result(Sym, Ty, DRE->getLocation());
}
Result
Clang2MapleVisitor::VisitFloatingLiteral(const clang::FloatingLiteral *Lit) {
MIRType *Ty = type2Mpl(Lit->getType());
llvm::APFloat Value = Lit->getValue();
ConstvalNode *Const = nullptr;
if (&Value.getSemantics() == &llvm::APFloat::IEEEsingle()) {
Const = Builder->CreateFloatConst(Value.convertToFloat());
} else if (&Value.getSemantics() == &llvm::APFloat::IEEEdouble()) {
Const = Builder->CreateDoubleConst(Value.convertToDouble());
} else if (&Value.getSemantics() == &llvm::APFloat::IEEEquad()) {
bool LosesInfo;
Value.convert(llvm::APFloat::IEEEdouble(),
llvm::APFloatBase::roundingMode::rmNearestTiesToAway,
&LosesInfo);
Const = Builder->CreateDoubleConst(Value.convertToDouble());
} else {
LogInfo::MapleLogger() << "Unexpected type of floating literal: "
<< Ty->GetPrimType() << "\n";
}
return Result(Const, Lit->getLocation(), Ty);
}
Result Clang2MapleVisitor::VisitImplicitValueInitExpr(
const clang::ImplicitValueInitExpr *IV) {
MIRType *Ty = type2Mpl(IV->getType());
MIRConst *Zero = createZero(Ty);
ConstvalNode *ZeroNode = Builder->CreateConstval(Zero);
return Result(ZeroNode, IV->getBeginLoc(), Ty);
}
Result Clang2MapleVisitor::VisitInitListExpr(const clang::InitListExpr *ILE) {
bool isStruct = ILE->getType()->isStructureType();
bool isUnion = ILE->getType()->isUnionType();
clang::RecordDecl *Record = ILE->getType()->getAsRecordDecl();
MIRType *Ty = type2Mpl(ILE->getType());
if (ILE->getNumInits() == 0) {
// Avoid generating an empty aggregate
if (Ty->GetSize() == 0) {
return Result(ILE->getBeginLoc());
}
MIRConst *Zero = createZero(Ty);
return Result(Builder->CreateConstval(Zero), ILE->getBeginLoc(), Ty);
}
// Ignore an init list expression for a scalar. For example:
// int x[3] = {{3}};
if (Ty->IsScalarType()) {
return Visit(ILE->getInit(0));
}
if (ILE->isConstantInitializer(*Context, false)) {
// Constant initializers return an agg const and may be used to initialize a
// global.
MIRAggConst *Agg;
if (ILE->isStringLiteralInit()) {
// String literals are a special case. 8 will return the
// complete agg, rather than processing it as an array.
MIRConst *Const = getInitializer(Ty, ILE->getInit(0));
ASSERT(Const->GetKind() == kConstAggConst,
"Expected agg const for string literal");
Agg = static_cast<MIRAggConst *>(Const);
} else {
Agg = Builder->GetCurrentFuncCodeMp()->New<MIRAggConst>(*Module, *Ty);
if (isStruct) {
unsigned InitIndex = 0;
for (const auto *FD : Record->fields()) {
if (FD->isUnnamedBitfield()) {
continue;
}
MIRType *InitTy = type2Mpl(ILE->getInit(InitIndex)->getType());
// Skip zero-sized structs
if (InitTy->GetSize() == 0) {
InitIndex++;
continue;
}
MIRConst *Const = getInitializer(InitTy, ILE->getInit(InitIndex));
ASSERT(Const, "Failed to get constant initializer for field");
if (FD->isBitField()) {
ASSERT(Const->GetKind() == kConstInt,
"Expected int for bitfield initialization");
MIRIntConst *IntConst = static_cast<MIRIntConst *>(Const);
unsigned long Mask = (1L << FD->getBitWidthValue(*Context)) - 1;
Const = GlobalTables::GetIntConstTable().GetOrCreateIntConst(
IntConst->GetValue() & Mask, *InitTy);
}
// If this agg const will be used as a global initializer, use the
// field index, but if it will be expanded in a function body, use
// the field ID.
FieldID Field;
if (Builder->GetCurrentFunction()) {
Field = FieldMap[Record][0][FD];
} else {
Field = FD->getFieldIndex() + 1;
}
Agg->AddItem(Const, Field);
InitIndex++;
}
} else if (isUnion) {
MIRType *InitTy = type2Mpl(ILE->getInit(0)->getType());
MIRConst *Const = getInitializer(InitTy, ILE->getInit(0));
const clang::FieldDecl *FD = ILE->getInitializedFieldInUnion();
Agg->AddItem(Const, FieldMap[Record][0][FD]);
} else {
for (unsigned i = 0; i < ILE->getNumInits(); ++i) {
MIRType *InitTy = type2Mpl(ILE->getInit(i)->getType());
MIRConst *Const = getInitializer(InitTy, ILE->getInit(i));
Agg->PushBack(Const);
}
}
}
ConstvalNode *ConstNode =
Builder->GetCurrentFuncCodeMp()->New<ConstvalNode>(PTY_agg, Agg);
return Result(ConstNode, ILE->getBeginLoc(), Ty);
} else {
Result Res(ILE->getBeginLoc());
// This will get translated into a series of assign nodes. For now, just
// return an intrinsic op node with all of the expressions. For structs and
// unions, the expressions are wrapped in an iread node to store the field
// ID.
MapleVector<BaseNode *> Ops(
Builder->GetCurrentFuncCodeMpAllocator()->Adapter());
if (isStruct) {
unsigned InitIndex = 0;
for (const auto *FD : Record->fields()) {
// Skip unnamed bitfields
if (FD->isUnnamedBitfield()) {
continue;
}
Result InitRes = Visit(ILE->getInit(InitIndex));
BaseNode *InitNode = getNodeAsRVal(InitRes);
Res.appendStmts(InitRes);
Ops.push_back(Builder->CreateExprIread(
*InitRes.getValueTy(), *InitRes.getValueTy(),
FieldMap[Record][0][FD], InitNode));
InitIndex++;
}
} else if (isUnion) {
Result InitRes = Visit(ILE->getInit(0));
BaseNode *InitNode = getNodeAsRVal(InitRes);
Res.appendStmts(InitRes);
const clang::FieldDecl *FD = ILE->getInitializedFieldInUnion();
Ops.push_back(
Builder->CreateExprIread(*InitRes.getValueTy(), *InitRes.getValueTy(),
FieldMap[Record][0][FD], InitNode));
} else {
for (unsigned i = 0; i < ILE->getNumInits(); ++i) {
Result InitRes = Visit(ILE->getInit(i));
BaseNode *InitNode = getNodeAsRVal(InitRes);
Res.appendStmts(InitRes);
Ops.push_back(InitNode);
}
}
IntrinsicopNode *N = Builder->CreateExprIntrinsicop(
INTRN_UNDEFINED, OP_intrinsicopwithtype, *Ty, Ops);
Res.setNode(N, Ty);
return Res;
}
}
Result
Clang2MapleVisitor::VisitIntegerLiteral(const clang::IntegerLiteral *Lit) {
MIRType *Ty = type2Mpl(Lit->getType());
ConstvalNode *Const = Builder->CreateIntConst(Lit->getValue().getSExtValue(),
Ty->GetPrimType());
return Result(Const, Lit->getLocation(), Ty);
}
Result Clang2MapleVisitor::VisitMemberExpr(const clang::MemberExpr *ME) {
clang::Expr *BaseExpr = ME->getBase();
clang::QualType QT = BaseExpr->getType();
if (ME->isArrow()) {
QT = QT->getPointeeType();
}
clang::RecordDecl *Record = QT->getAsRecordDecl();
Result BaseRes = Visit(BaseExpr);
const clang::FieldDecl *FD =
llvm::dyn_cast<clang::FieldDecl>(ME->getMemberDecl());
ASSERT(FD, "member is not a FieldDecl");
// Handle member access through a pointer
if (ME->isArrow()) {
BaseNode *Base = getNodeAsRVal(BaseRes);
Result Res(Base, type2Mpl(BaseExpr->getType()), type2Mpl(ME->getType()),
ME->getExprLoc());
Res.appendStmts(BaseRes);
Res.setBaseRecordDecl(Record);
ASSERT(FieldMap.find(Record) != FieldMap.end() &&
FieldMap[Record].find(0) != FieldMap[Record].end() &&
FieldMap[Record][0].find(FD) != FieldMap[Record][0].end(),
"Structure or field not in map");
Res.setField(FieldMap[Record][0][FD]);
return Res;
} else {
Record = BaseRes.setBaseRecordDecl(Record);
ASSERT(FieldMap.find(Record) != FieldMap.end() &&
FieldMap[Record].find(BaseRes.getField()) !=
FieldMap[Record].end() &&
FieldMap[Record][BaseRes.getField()].find(FD) !=
FieldMap[Record][BaseRes.getField()].end(),
"Structure or field not in map");
BaseRes.setField(FieldMap[Record][BaseRes.getField()][FD]);
BaseRes.setValueTy(type2Mpl(ME->getType()), true);
return BaseRes;
}
}
Result Clang2MapleVisitor::VisitOffsetOfExpr(const clang::OffsetOfExpr *OOE) {
size_t Offset = 0;
clang::QualType QT;
for (unsigned int i = 0; i < OOE->getNumComponents(); i++) {
const clang::OffsetOfNode &OON = OOE->getComponent(i);
switch (OON.getKind()) {
case clang::OffsetOfNode::Field: {
clang::FieldDecl *Field = OON.getField();
QT = Field->getType();
uint64_t FieldOffset = Context->getFieldOffset(Field) / 8;
LogInfo::MapleLogger() << OON.getFieldName()->getName().str()
<< " has offset " << FieldOffset << "\n";
Offset += FieldOffset;
} break;
case clang::OffsetOfNode::Array: {
const clang::Expr *E = OOE->getIndexExpr(OON.getArrayExprIndex());
clang::Expr::EvalResult IndexVal;
if (E->EvaluateAsInt(IndexVal, *Context)) {
llvm::APSInt Index = IndexVal.Val.getInt();
const clang::Type *ElementType = QT->getPointeeOrArrayElementType();
clang::CharUnits ElementSize = Context->getTypeSizeInChars(ElementType);
Offset += (Index.getExtValue() * ElementSize.getQuantity());
LogInfo::MapleLogger() << "array access: " << Index.getExtValue()
<< " * " << ElementSize.getQuantity() << "\n";
} else {
ASSERT(false, "Non-constant array index in offsetof expressions");
}
} break;
default:
OOE->dump();
ASSERT(false, "Unsupported offsetof");
}
}
return Result(Builder->CreateIntConst(Offset, PTY_u64), OOE->getOperatorLoc(),
type2Mpl(OOE->getType()));
}
Result
Clang2MapleVisitor::VisitOpaqueValueExpr(const clang::OpaqueValueExpr *OVE) {
MIRType *Ty = type2Mpl(OVE->getType());
Result SourceRes = Visit(OVE->getSourceExpr());
std::string Name = "_opaque." + std::to_string(OVE->getID(*Context));
MIRSymbol *Temp = Builder->GetLocalDecl(Name);
if (!Temp) {
Temp = Builder->GetOrCreateLocalDecl(Name, *Ty);
StmtNode *TempAssign =
Builder->CreateStmtDassign(*Temp, 0, getNodeAsRVal(SourceRes));
TempAssign->SetSrcPos(sourceLocation2Mpl(OVE->getBeginLoc()));
Result Res(Temp, Ty, OVE->getBeginLoc());
Res.appendStmts(SourceRes);
Res.appendStmtBefore(TempAssign);
return Res;
}
Result Res(Temp, Ty, OVE->getBeginLoc());
Res.appendStmts(SourceRes);
return Res;
}
Result Clang2MapleVisitor::VisitParenExpr(const clang::ParenExpr *PE) {
return Visit(PE->getSubExpr());
}
Result
Clang2MapleVisitor::VisitPredefinedExpr(const clang::PredefinedExpr *PE) {
return Visit(PE->getFunctionName());
}
Result Clang2MapleVisitor::VisitStmtExpr(const clang::StmtExpr *SE) {
Result Res(SE->getBeginLoc());
const clang::CompoundStmt *CS = SE->getSubStmt();
// All of the statements from the compound statement should run before the
// last expression, which should be returned from this visitor.
for (clang::Stmt *S : CS->body()) {
// Do not include the last statement.
if (S == CS->body_back())
break;
Result SRes = Visit(S);
appendResultBefore(Res, SRes);
}
// Now add the last expression as the node returned for this expression.
Result LastRes = Visit(CS->body_back());
Res.appendStmts(LastRes);
Res.setResult(LastRes);
return Res;
}
Result Clang2MapleVisitor::VisitStringLiteral(const clang::StringLiteral *Lit) {
MIRType *Ty = type2Mpl(Lit->getType());
ConstvalNode *ConstVal = nullptr;
if (Lit->isAscii()) {
UStrIdx StrIdx = GlobalTables::GetUStrTable().GetOrCreateStrIdxFromName(
Lit->getString().str());
ConststrNode *Const =
Module->GetMemPool()->New<ConststrNode>(PointerPrimTy, StrIdx);
return Result(Const, Lit->getBeginLoc(), Ty);
} else if (Lit->isWide()) {
ConstVal = Module->CurFuncCodeMemPool()->New<ConstvalNode>();
MIRAggConst *Const =
Module->CurFuncCodeMemPool()->New<MIRAggConst>(*Module, *Ty);
for (unsigned int i = 0; i < Lit->getLength(); i++) {
Const->PushBack(GlobalTables::GetIntConstTable().GetOrCreateIntConst(
Lit->getCodeUnit(i),
*GlobalTables::GetTypeTable().GetPrimType(PTY_i32)));
}
ConstVal->SetPrimType(PTY_agg);
ConstVal->SetConstVal(Const);
} else {
Lit->dump();
ASSERT(false, "Unsupported string type");
}
return Result(ConstVal, Lit->getBeginLoc(), Ty);
}
Result Clang2MapleVisitor::VisitTypeTraitExpr(const clang::TypeTraitExpr *TTE) {
MIRType *Ty = type2Mpl(TTE->getType());
return Result(Builder->CreateIntConst(TTE->getValue() ? 1 : 0, PTY_i32),
TTE->getBeginLoc(), Ty);
}
Result Clang2MapleVisitor::VisitUnaryExprOrTypeTraitExpr(
const clang::UnaryExprOrTypeTraitExpr *UETT) {
MIRType *Ty = type2Mpl(UETT->getType());
clang::QualType QT;
if (UETT->isArgumentType()) {
QT = UETT->getArgumentType();
} else {
QT = UETT->getArgumentExpr()->getType();
}
switch (UETT->getKind()) {
case clang::UETT_SizeOf: {
// C11 specification: ISO/IEC 9899:201x
// $ 6.5.3.4
// "If the type of the operand is a variable length array type,
// the operand is evaluated; otherwise, the operand is not evaluated
// and the result is an integer constant."
if (QT->isVariableArrayType()) {
return buildExprToComputeSizeFromVLA(UETT->getBeginLoc(), QT);
}
clang::CharUnits Size = Context->getTypeSizeInChars(QT);
return Result(Builder->GetConstInt(Size.getQuantity()), UETT->getBeginLoc(),
Ty);
} break;
case clang::UETT_AlignOf:
case clang::UETT_PreferredAlignOf: {
clang::CharUnits Align = Context->getTypeAlignInChars(QT);
return Result(Builder->GetConstInt(Align.getQuantity()),
UETT->getRParenLoc(), Ty);
} break;
default:
LogInfo::MapleLogger()
<< "Warning: Unhandled kind of UnaryExprOrTypeTraitExpr: "
<< UETT->getKind() << "\n";
return Result(UETT->getBeginLoc());
}
}
Result Clang2MapleVisitor::VisitUnaryOperator(const clang::UnaryOperator *UO) {
Result SubExpr = Visit(UO->getSubExpr());
MIRType *ResTy = type2Mpl(UO->getType());
BaseNode *UONode = nullptr;
switch (UO->getOpcode()) {
case clang::UO_Deref: {
// Deref has to be handled by the parent. If it is on the left-hand side of
// an assignment, then the assignment becomes an iassign, but if it is on
// the right, then it needs an iread.
MIRType *SubTy = type2Mpl(UO->getSubExpr()->getType());
Result Res(getNodeAsRVal(SubExpr), SubTy, ResTy, UO->getExprLoc());
Res.appendStmts(SubExpr);
return Res;
}
case clang::UO_AddrOf: {
if (SubExpr.isSym()) {
MIRSymbol *Sym = SubExpr.getSym();
if (Sym->GetSKind() == kStFunc) {
UONode = Builder->CreateExprAddroffunc(Sym->GetFunction()->GetPuidx());
} else {
UONode = Builder->CreateExprAddrof(SubExpr.getField(), *Sym);
}
UONode->SetPrimType(PointerPrimTy);
break;
} else {
BaseNode *N = getNodeAsRVal(SubExpr);
if (N->GetOpCode() == OP_array) {
UONode = N;
break;
} else if (N->GetOpCode() == OP_iread) {
IreadNode *IRead = static_cast<IreadNode *>(N);
if (N->Opnd(0)->GetOpCode() == OP_array && !IRead->GetFieldID()) {
UONode = N->Opnd(0);
} else {
UONode = Builder->CreateExprIaddrof(ResTy->GetPrimType(),
IRead->GetTyIdx(),
IRead->GetFieldID(), N->Opnd(0));
UONode->SetPrimType(PointerPrimTy);
}
break;
}
}
LogInfo::MapleLogger()
<< "Warning: Unhandled expression in AddrOf operation\n";
break;
}
case clang::UO_Extension:
// This is just a wrapper to indicate a GNU extension.
return SubExpr;
case clang::UO_Plus:
return SubExpr;
case clang::UO_Minus:
UONode = Builder->CreateExprUnary(OP_neg, *ResTy, getNodeAsRVal(SubExpr));
break;
case clang::UO_Not:
UONode = Builder->CreateExprUnary(OP_bnot, *ResTy, getNodeAsRVal(SubExpr));
break;
case clang::UO_LNot:
UONode = exprToNotCond(getNodeAsRVal(SubExpr));
break;
case clang::UO_PostInc:
case clang::UO_PostDec:
case clang::UO_PreInc:
case clang::UO_PreDec: {
size_t IncAmount = 1;
if (ResTy->GetKind() == kTypePointer) {
IncAmount = static_cast<MIRPtrType *>(ResTy)->GetPointedType()->GetSize();
}
BaseNode *IncAmountNode;
if (PrimitiveType(ResTy->GetPrimType()).IsInteger()) {
IncAmountNode =
Builder->CreateIntConst(IncAmount, (ResTy->GetKind() == kTypePointer)
? IntPointerTy->GetPrimType()
: ResTy->GetPrimType());
} else if (ResTy->GetPrimType() == PTY_f32) {
IncAmountNode = Builder->CreateFloatConst(1.0f);
} else if (ResTy->GetPrimType() == PTY_f64) {
IncAmountNode = Builder->CreateDoubleConst(1.0);
} else {
ResTy->Dump(0);
ASSERT(false, "Unexpected type of pre/post inc/dec");
}
BaseNode *BinNode =
Builder->CreateExprBinary(UO->isDecrementOp() ? OP_sub : OP_add, *ResTy,
getNodeAsRVal(SubExpr), IncAmountNode);
if (UO->isPrefix()) {
Result Res(getNodeAsRVal(SubExpr), UO->getExprLoc(), ResTy, true);
Res.appendStmts(SubExpr);
StmtNode *Assign = nullptr;
if (SubExpr.isSym()) {
Assign = Builder->CreateStmtDassign(*SubExpr.getSym(),
SubExpr.getField(), BinNode);
} else if (SubExpr.isDeref()) {
Assign =
Builder->CreateStmtIassign(*SubExpr.getAddrTy(), SubExpr.getField(),
SubExpr.getAddr(), BinNode);
} else {
LogInfo::MapleLogger()
<< "Warning: Unhandled expression in prefix operation\n";
getNodeAsRVal(SubExpr)->Dump();
return Result(UO->getExprLoc());
}
Assign->SetSrcPos(sourceLocation2Mpl(UO->getExprLoc()));
Res.appendStmtBefore(Assign);
return Res;
} else {
MIRSymbol *Temp = Builder->GetOrCreateLocalDecl(
"post." + std::to_string(UO->getID(*Context)), *ResTy);
Result Res(Temp, ResTy, UO->getExprLoc(), true);
Res.appendStmts(SubExpr);
StmtNode *TempAssign =
Builder->CreateStmtDassign(*Temp, 0, getNodeAsRVal(SubExpr));
TempAssign->SetSrcPos(sourceLocation2Mpl(UO->getExprLoc()));
Res.appendStmtBefore(TempAssign);
StmtNode *Assign = nullptr;
if (SubExpr.isSym()) {
Assign = Builder->CreateStmtDassign(*SubExpr.getSym(),
SubExpr.getField(), BinNode);
} else if (SubExpr.isDeref()) {
Assign =
Builder->CreateStmtIassign(*SubExpr.getAddrTy(), SubExpr.getField(),
SubExpr.getAddr(), BinNode);
} else {
LogInfo::MapleLogger()
<< "Warning: Unhandled expression in postfix operation\n";
getNodeAsRVal(SubExpr)->Dump();
return Result(UO->getExprLoc());
}
Assign->SetSrcPos(sourceLocation2Mpl(UO->getExprLoc()));
Res.appendStmtBefore(Assign);
return Res;
}
}
default:
UO->dump();
ASSERT(false, "Unhandled unary opcode");
}
Result Res(UONode, UO->getExprLoc(), ResTy);
Res.appendStmts(SubExpr);
return Res;
}
BaseNode *Clang2MapleVisitor::readField(Result BaseRes, FieldID Field,
MIRType *Ty) {
if (BaseRes.isSym()) {
return Builder->CreateExprDread(*Ty, BaseRes.getField() + Field,
*BaseRes.getSym());
} else {
return Builder->CreateExprIread(*Ty, *BaseRes.getAddrTy(),
BaseRes.getField() + Field,
BaseRes.getNode());
}
}
StmtNode *Clang2MapleVisitor::writeField(Result BaseRes, FieldID Field,
BaseNode *Src) {
if (BaseRes.isSym()) {
return Builder->CreateStmtDassign(*BaseRes.getSym(),
BaseRes.getField() + Field, Src);
} else {
return Builder->CreateStmtIassign(*BaseRes.getAddrTy(),
BaseRes.getField() + Field,
BaseRes.getNode(), Src);
}
}
Result Clang2MapleVisitor::VisitVAArgExpr(const clang::VAArgExpr *VAArg) {
ASSERT(Context->getTargetInfo().getBuiltinVaListKind() ==
clang::TargetInfo::AArch64ABIBuiltinVaList,
"Architecture not yet supported for varargs");
// This sequence of instructions implements the pseducode from
// https://developer.arm.com/documentation/ihi0055/d/?lang=en#the-va-arg-macro
MIRType *ArgTy = type2Mpl(VAArg->getType());
MIRPtrType *PointerToArgTy = static_cast<MIRPtrType *>(
GlobalTables::GetTypeTable().GetOrCreatePointerType(*ArgTy,
PointerPrimTy));
SrcPosition SrcPos = sourceLocation2Mpl(VAArg->getBeginLoc());
MIRType *IntTy =
GlobalTables::GetTypeTable().GetTypeFromTyIdx(TyIdx(PTY_i32));
MIRSymbol *Offs = Builder->GetOrCreateLocalDecl(
"va_offs." + std::to_string(++UnnamedCount), *IntTy);
MIRSymbol *ArgPtr = Builder->GetOrCreateLocalDecl(
"va_arg_ptr." + std::to_string(++UnnamedCount), *PointerToArgTy);
Result Res(VAArg->getBeginLoc());
Result ApRes = Visit(VAArg->getSubExpr());
Res.appendStmts(ApRes);
MIRStructType *ApListTy =
static_cast<MIRStructType *>(type2Mpl(VAArg->getSubExpr()->getType()));
LabelIdx OnStackLabel = Builder->GetOrCreateMIRLabel(
"_vaarg_on_stack." + std::to_string(++UnnamedCount));
LabelIdx EndLabel = Builder->GetOrCreateMIRLabel(
"_vaarg_end." + std::to_string(++UnnamedCount));
// If the argument type is a Composite Type that is larger than 16 bytes,
// then the argument is copied to memory allocated by the caller and the
// argument is replaced by a pointer to the copy.
bool CopyToStack = false;
if (ArgTy->IsStructType() && ArgTy->GetSize() > 16) {
CopyToStack = true;
ArgTy = PointerToArgTy;
PointerToArgTy = static_cast<MIRPtrType *>(
GlobalTables::GetTypeTable().GetOrCreatePointerType(*ArgTy));
}
// if (type passed in general registers)
if (passInGeneralRegisters(ArgTy)) {
// offs = ap.__gr_offs
StmtNode *S =
Builder->CreateStmtDassign(*Offs, 0, readField(ApRes, 4, IntTy));
S->SetSrcPos(SrcPos);
Res.appendStmtBefore(S);
// if (offs >= 0), goto on_stack
ConstvalNode *ZeroNode = Builder->GetConstInt(0);
BaseNode *ReadOffs = Builder->CreateExprDread(*IntTy, 0, *Offs);
BaseNode *Cond =
Builder->CreateExprCompare(OP_ge, *IntTy, *IntTy, ReadOffs, ZeroNode);
StmtNode *CondBranch =
Builder->CreateStmtCondGoto(Cond, OP_brtrue, OnStackLabel);
CondBranch->SetSrcPos(SrcPos);
Res.appendStmtBefore(CondBranch);
// if (alignof(type) > 8) offs = (offs + 15) & -16;
if (ArgTy->GetAlign() > 8) {
BaseNode *SumNode = Builder->CreateExprBinary(
OP_add, *IntTy, Builder->CreateExprDread(*IntTy, 0, *Offs),
Builder->GetConstInt(15));
BaseNode *AndNode = Builder->CreateExprBinary(OP_band, *IntTy, SumNode,
Builder->GetConstInt(-16));
StmtNode *Assign = Builder->CreateStmtDassign(*Offs, 0, AndNode);
Assign->SetSrcPos(SrcPos);
Res.appendStmtBefore(Assign);
}
// nreg = (sizeof(type) + 7) / 8;
int Nreg = (ArgTy->GetSize() + 7) / 8;
// ap.__gr_offs = offs + (nreg * 8);
BaseNode *OffsSum = Builder->CreateExprBinary(
OP_add, *IntTy, Builder->CreateExprDread(*IntTy, 0, *Offs),
Builder->GetConstInt(Nreg * 8));
StmtNode *UpdateOffs = writeField(ApRes, 4, OffsSum);
UpdateOffs->SetSrcPos(SrcPos);
Res.appendStmtBefore(UpdateOffs);
// if (ap.__gr_offs > 0) goto on_stack;
ZeroNode = Builder->GetConstInt(0);
ReadOffs = readField(ApRes, 4, IntTy);
Cond =
Builder->CreateExprCompare(OP_gt, *IntTy, *IntTy, ReadOffs, ZeroNode);
CondBranch = Builder->CreateStmtCondGoto(Cond, OP_brtrue, OnStackLabel);
CondBranch->SetSrcPos(SrcPos);
Res.appendStmtBefore(CondBranch);
// return *(type *)(ap.__gr_top + offs);
BaseNode *ArgAddr = Builder->CreateExprBinary(
OP_add, *ApListTy->GetFieldType(2),
readField(ApRes, 2, ApListTy->GetFieldType(2)),
Builder->CreateExprTypeCvt(OP_cvt, *ApListTy->GetFieldType(2), *IntTy,
Builder->CreateExprDread(*IntTy, 0, *Offs)));
StmtNode *AssignPtr = Builder->CreateStmtDassign(*ArgPtr, 0, ArgAddr);
AssignPtr->SetSrcPos(SrcPos);
Res.appendStmtBefore(AssignPtr);
GotoNode *GoToEnd = Builder->CreateStmtGoto(OP_goto, EndLabel);
GoToEnd->SetSrcPos(SrcPos);
Res.appendStmtBefore(GoToEnd);
}
// else if (type is an HFA or an HVA)
// TODO: Handle HVA
else if (MIRType *ElemTy = isHomogenousAggregate(ArgTy)) {
// offs = ap.__vr_offs
StmtNode *S =
Builder->CreateStmtDassign(*Offs, 0, readField(ApRes, 5, IntTy));
S->SetSrcPos(SrcPos);
Res.appendStmtBefore(S);
// if (offs >= 0), goto on_stack
ConstvalNode *ZeroNode = Builder->GetConstInt(0);
BaseNode *ReadOffs = Builder->CreateExprDread(*IntTy, 0, *Offs);
BaseNode *Cond =
Builder->CreateExprCompare(OP_ge, *IntTy, *IntTy, ReadOffs, ZeroNode);
StmtNode *CondBranch =
Builder->CreateStmtCondGoto(Cond, OP_brtrue, OnStackLabel);
CondBranch->SetSrcPos(SrcPos);
Res.appendStmtBefore(CondBranch);
// nreg = sizeof(type) / sizeof(ftype);
int Nreg = ArgTy->GetSize() / ElemTy->GetSize();
// ap.__vr_offs = offs + (nreg * 16);
BaseNode *OffsSum = Builder->CreateExprBinary(
OP_add, *IntTy, Builder->CreateExprDread(*IntTy, 0, *Offs),
Builder->GetConstInt(Nreg * 16));
StmtNode *UpdateOffs = writeField(ApRes, 5, OffsSum);
UpdateOffs->SetSrcPos(SrcPos);
Res.appendStmtBefore(UpdateOffs);
// if (ap.__vr_offs > 0) goto on_stack;
ZeroNode = Builder->GetConstInt(0);
ReadOffs = readField(ApRes, 5, IntTy);
Cond =
Builder->CreateExprCompare(OP_gt, *IntTy, *IntTy, ReadOffs, ZeroNode);
CondBranch = Builder->CreateStmtCondGoto(Cond, OP_brtrue, OnStackLabel);
CondBranch->SetSrcPos(SrcPos);
Res.appendStmtBefore(CondBranch);
// for (i = 0; i < nreg; i++, offs += 16)
// ha.field[i] = *((ftype *)(ap.__vr_top + offs));
// return ha;
BaseNode *ArgAddr = Builder->CreateExprBinary(
OP_add, *ApListTy->GetFieldType(2),
readField(ApRes, 3, ApListTy->GetFieldType(3)),
Builder->CreateExprTypeCvt(OP_cvt, *ApListTy->GetFieldType(3), *IntTy,
Builder->CreateExprDread(*IntTy, 0, *Offs)));
StmtNode *AssignPtr = Builder->CreateStmtDassign(*ArgPtr, 0, ArgAddr);
AssignPtr->SetSrcPos(SrcPos);
Res.appendStmtBefore(AssignPtr);
MIRStructType *StructTy = static_cast<MIRStructType *>(ArgTy);
MIRSymbol *Ha = Builder->CreateLocalDecl(
"vaarg_ha." + std::to_string(++UnnamedCount), *StructTy);
unsigned SrcOffset = 0;
for (size_t FID = 1; FID <= StructTy->NumberOfFieldIDs(); FID++) {
MIRType *FieldTy = StructTy->GetFieldType(FID);
MIRType *PointerToFieldTy =
GlobalTables::GetTypeTable().GetOrCreatePointerType(*FieldTy,
PointerPrimTy);
if (FieldTy->IsStructType()) {
continue;
}
if (FieldTy->GetKind() == kTypeArray) {
MIRArrayType *ArrayTy = static_cast<MIRArrayType *>(FieldTy);
MIRType *PointerToElemTy =
GlobalTables::GetTypeTable().GetOrCreatePointerType(*ElemTy,
PointerPrimTy);
for (size_t ElemID = 0; ElemID < ArrayTy->GetSizeArrayItem(0);
ElemID++) {
BaseNode *BaseAddr = Builder->CreateExprAddrof(FID, *Ha);
BaseAddr->SetPrimType(PointerPrimTy);
BaseNode *IndexNode =
Builder->CreateIntConst(ElemID, IntPointerTy->GetPrimType());
ArrayNode *Array =
Builder->CreateExprArray(*ArrayTy, BaseAddr, IndexNode);
Array->SetBoundsCheck(false);
Array->SetPrimType(PointerPrimTy);
StmtNode *AssignElem = Builder->CreateStmtIassign(
*PointerToElemTy, 0, Array,
Builder->CreateExprIread(
*FieldTy, *PointerToElemTy, 0,
Builder->CreateExprBinary(
OP_add, *PointerToElemTy,
Builder->CreateExprDread(*PointerToArgTy, *ArgPtr),
Builder->CreateIntConst(SrcOffset, PointerPrimTy))));
AssignElem->SetSrcPos(SrcPos);
Res.appendStmtBefore(AssignElem);
SrcOffset += 16;
}
} else {
StmtNode *AssignField = Builder->CreateStmtDassign(
*Ha, FID,
Builder->CreateExprIread(
*FieldTy, *PointerToFieldTy, 0,
Builder->CreateExprBinary(
OP_add, *PointerToFieldTy,
Builder->CreateExprDread(*PointerToArgTy, *ArgPtr),
Builder->CreateIntConst(SrcOffset, PointerPrimTy))));
AssignField->SetSrcPos(SrcPos);
Res.appendStmtBefore(AssignField);
SrcOffset += 16;
}
}
AssignPtr = Builder->CreateStmtDassign(*ArgPtr, 0,
Builder->CreateExprAddrof(0, *Ha));
AssignPtr->SetSrcPos(SrcPos);
Res.appendStmtBefore(AssignPtr);
GotoNode *GoToEnd = Builder->CreateStmtGoto(OP_goto, EndLabel);
GoToEnd->SetSrcPos(SrcPos);
Res.appendStmtBefore(GoToEnd);
}
// else if (type passed in fp/simd registers)
// TODO: handle simd registers
else if (passInFloatRegisters(ArgTy)) {
// offs = ap.__vr_offs
StmtNode *S =
Builder->CreateStmtDassign(*Offs, 0, readField(ApRes, 5, IntTy));
S->SetSrcPos(SrcPos);
Res.appendStmtBefore(S);
// if (offs >= 0), goto on_stack
ConstvalNode *ZeroNode = Builder->GetConstInt(0);
BaseNode *ReadOffs = Builder->CreateExprDread(*IntTy, 0, *Offs);
BaseNode *Cond =
Builder->CreateExprCompare(OP_ge, *IntTy, *IntTy, ReadOffs, ZeroNode);
StmtNode *CondBranch =
Builder->CreateStmtCondGoto(Cond, OP_brtrue, OnStackLabel);
CondBranch->SetSrcPos(SrcPos);
Res.appendStmtBefore(CondBranch);
// nreg = (sizeof(type) + 15) / 16;
// Note that we use 7, 8 here instead of 15, 16. This is because the
// sizeof a double is 8, but for varargs, it uses 16.
int Nreg = (ArgTy->GetSize() + 7) / 8;
// ap.__vr_offs = offs + (nreg * 16);
BaseNode *OffsSum = Builder->CreateExprBinary(
OP_add, *IntTy, Builder->CreateExprDread(*IntTy, 0, *Offs),
Builder->GetConstInt(Nreg * 16));
StmtNode *UpdateOffs = writeField(ApRes, 5, OffsSum);
UpdateOffs->SetSrcPos(SrcPos);
Res.appendStmtBefore(UpdateOffs);
// if (ap.__vr_offs > 0) goto on_stack;
ZeroNode = Builder->GetConstInt(0);
ReadOffs = readField(ApRes, 5, IntTy);
Cond =
Builder->CreateExprCompare(OP_gt, *IntTy, *IntTy, ReadOffs, ZeroNode);
CondBranch = Builder->CreateStmtCondGoto(Cond, OP_brtrue, OnStackLabel);
CondBranch->SetSrcPos(SrcPos);
Res.appendStmtBefore(CondBranch);
// return *(type *)(ap.__vr_top + offs);
BaseNode *ArgAddr = Builder->CreateExprBinary(
OP_add, *ApListTy->GetFieldType(2),
readField(ApRes, 3, ApListTy->GetFieldType(3)),
Builder->CreateExprTypeCvt(OP_cvt, *ApListTy->GetFieldType(3), *IntTy,
Builder->CreateExprDread(*IntTy, 0, *Offs)));
StmtNode *AssignPtr = Builder->CreateStmtDassign(*ArgPtr, 0, ArgAddr);
AssignPtr->SetSrcPos(SrcPos);
Res.appendStmtBefore(AssignPtr);
GotoNode *GoToEnd = Builder->CreateStmtGoto(OP_goto, EndLabel);
GoToEnd->SetSrcPos(SrcPos);
Res.appendStmtBefore(GoToEnd);
}
// on_stack:
StmtNode *LabelStmt = Builder->CreateStmtLabel(OnStackLabel);
LabelStmt->SetSrcPos(SrcPos);
Res.appendStmtBefore(LabelStmt);
// intptr_t arg = ap.__stack;
StmtNode *StackBase =
Builder->CreateStmtDassign(*ArgPtr, 0, readField(ApRes, 1, IntPointerTy));
StackBase->SetSrcPos(SrcPos);
Res.appendStmtBefore(StackBase);
// if (alignof(type) > 8) arg = (arg + 15) & -16;
if (ArgTy->GetAlign() > 8) {
BaseNode *SumNode = Builder->CreateExprBinary(
OP_add, *IntPointerTy,
Builder->CreateExprDread(*IntPointerTy, 0, *ArgPtr),
Builder->GetConstInt(15));
BaseNode *AndNode = Builder->CreateExprBinary(
OP_band, *IntPointerTy, SumNode, Builder->GetConstInt(-16));
StmtNode *Assign = Builder->CreateStmtDassign(*ArgPtr, 0, AndNode);
Assign->SetSrcPos(SrcPos);
Res.appendStmtBefore(Assign);
}
// ap.__stack = (void *)((arg + sizeof(type) + 7) & -8);
BaseNode *CalcArg = Builder->CreateExprBinary(
OP_add, *IntPointerTy,
Builder->CreateExprDread(*IntPointerTy, 0, *ArgPtr),
Builder->CreateIntConst(ArgTy->GetSize() + 7,
IntPointerTy->GetPrimType()));
CalcArg = Builder->CreateExprBinary(
OP_band, *IntPointerTy, CalcArg,
Builder->CreateIntConst(-8, IntPointerTy->GetPrimType()));
StmtNode *StackAssign = writeField(ApRes, 1, CalcArg);
StackAssign->SetSrcPos(SrcPos);
Res.appendStmtBefore(StackAssign);
// return *(type *)arg;
// end:
LabelStmt = Builder->CreateStmtLabel(EndLabel);
LabelStmt->SetSrcPos(SrcPos);
Res.appendStmtBefore(LabelStmt);
BaseNode *Arg = Builder->CreateExprIread(
*ArgTy, *PointerToArgTy, 0,
Builder->CreateExprDread(*PointerToArgTy, 0, *ArgPtr));
// If the argument type is a Composite Type that is larger than 16 bytes,
// then the argument is copied to memory allocated by the caller and the
// argument is replaced by a pointer to the copy.
if (CopyToStack) {
PointerToArgTy = static_cast<MIRPtrType *>(ArgTy);
ArgTy = PointerToArgTy->GetPointedType();
Arg = Builder->CreateExprIread(*ArgTy, *PointerToArgTy, 0, Arg);
}
Res.setNode(Arg, ArgTy);
return Res;
}
//
// Private methods
//
void Clang2MapleVisitor::setupBuiltinTypes(void) {
std::map<const clang::Type *, TyIdx> BuiltinTypes = {
{Context->BoolTy.getTypePtr(),
GlobalTables::GetTypeTable().GetUInt1()->GetTypeIndex()},
{Context->CharTy.getTypePtr(),
GlobalTables::GetTypeTable().GetInt8()->GetTypeIndex()},
{Context->SignedCharTy.getTypePtr(),
GlobalTables::GetTypeTable().GetInt8()->GetTypeIndex()},
{Context->ShortTy.getTypePtr(),
GlobalTables::GetTypeTable().GetInt16()->GetTypeIndex()},
{Context->IntTy.getTypePtr(),
GlobalTables::GetTypeTable().GetInt32()->GetTypeIndex()},
{Context->LongLongTy.getTypePtr(),
GlobalTables::GetTypeTable().GetInt64()->GetTypeIndex()},
// __int128 is handled as an i64
{Context->Int128Ty.getTypePtr(),
GlobalTables::GetTypeTable().GetInt64()->GetTypeIndex()},
{Context->UnsignedCharTy.getTypePtr(),
GlobalTables::GetTypeTable().GetUInt8()->GetTypeIndex()},
{Context->UnsignedShortTy.getTypePtr(),
GlobalTables::GetTypeTable().GetUInt16()->GetTypeIndex()},
{Context->UnsignedIntTy.getTypePtr(),
GlobalTables::GetTypeTable().GetUInt32()->GetTypeIndex()},
{Context->UnsignedLongLongTy.getTypePtr(),
GlobalTables::GetTypeTable().GetUInt64()->GetTypeIndex()},
// unsigned __int128 is handled as a u64
{Context->UnsignedInt128Ty.getTypePtr(),
GlobalTables::GetTypeTable().GetUInt64()->GetTypeIndex()},
{Context->FloatTy.getTypePtr(),
GlobalTables::GetTypeTable().GetFloat()->GetTypeIndex()},
{Context->DoubleTy.getTypePtr(),
GlobalTables::GetTypeTable().GetDouble()->GetTypeIndex()},
// long double is handled as a double
{Context->LongDoubleTy.getTypePtr(),
GlobalTables::GetTypeTable().GetDouble()->GetTypeIndex()},
{Context->FloatComplexTy.getTypePtr(), TyIdx(PTY_c64)},
{Context->DoubleComplexTy.getTypePtr(), TyIdx(PTY_c128)},
{Context->VoidTy.getTypePtr(),
GlobalTables::GetTypeTable().GetVoid()->GetTypeIndex()}};
TypeMap.insert(BuiltinTypes.begin(), BuiltinTypes.end());
if (Context->getTypeSize(Context->LongTy) == 32) {
TypeMap[Context->LongTy.getTypePtr()] =
GlobalTables::GetTypeTable().GetInt32()->GetTypeIndex();
TypeMap[Context->UnsignedLongTy.getTypePtr()] =
GlobalTables::GetTypeTable().GetUInt32()->GetTypeIndex();
PointerPrimTy = PTY_a32;
IntPointerTy = GlobalTables::GetTypeTable().GetUInt32();
} else {
TypeMap[Context->LongTy.getTypePtr()] =
GlobalTables::GetTypeTable().GetInt64()->GetTypeIndex();
TypeMap[Context->UnsignedLongTy.getTypePtr()] =
GlobalTables::GetTypeTable().GetUInt64()->GetTypeIndex();
PointerPrimTy = PTY_a64;
IntPointerTy = GlobalTables::GetTypeTable().GetUInt64();
}
}
TyIdx Clang2MapleVisitor::type2MplIdx(clang::QualType QT) {
const clang::Type *Ty = QT.getDesugaredType(*Context).getTypePtr();
auto it = TypeMap.find(Ty);
if (it != TypeMap.end()) {
return it->second;
}
// Create a new function type
if (const clang::FunctionType *FT = llvm::dyn_cast<clang::FunctionType>(Ty)) {
TyIdx ReturnTy = type2MplIdx(FT->getReturnType());
std::vector<TyIdx> ParamTypeList;
std::vector<TypeAttrs> ParamAttrsList;
bool IsVariadic = false;
if (const clang::FunctionProtoType *FPT =
llvm::dyn_cast<clang::FunctionProtoType>(Ty)) {
if (GlobalTables::GetTypeTable().GetTypeFromTyIdx(ReturnTy)->GetSize() >
16) {
MIRType *ReturnTyPtr =
GlobalTables::GetTypeTable().GetOrCreatePointerType(ReturnTy,
PointerPrimTy);
ParamTypeList.push_back(ReturnTyPtr->GetTypeIndex());
ParamAttrsList.push_back(TypeAttrs());
ReturnTy = GlobalTables::GetTypeTable().GetVoid()->GetTypeIndex();
}
for (const clang::QualType &Param : FPT->param_types()) {
ParamTypeList.push_back(type2MplIdx(Param));
ParamAttrsList.push_back(TypeAttrs()); // TODO: Add attributes
}
IsVariadic = FPT->isVariadic();
}
MIRType *MTy = GlobalTables::GetTypeTable().GetOrCreateFunctionType(
ReturnTy, ParamTypeList, ParamAttrsList, IsVariadic);
TypeMap.insert({FT, MTy->GetTypeIndex()});
return MTy->GetTypeIndex();
} else if (const clang::PointerType *PtrTy =
llvm::dyn_cast<clang::PointerType>(Ty)) {
// Create a pointer type from the pointee type
TyIdx PointeeTyIdx = type2MplIdx(PtrTy->getPointeeType());
MIRPtrType *MTy = static_cast<MIRPtrType *>(
GlobalTables::GetTypeTable().GetOrCreatePointerType(PointeeTyIdx,
PointerPrimTy));
MTy->SetPrimType(PointerPrimTy);
// If this is a pointer to a type which is not yet fully-defined, record
// it to be updated later.
if (GlobalTables::GetTypeTable()
.GetTypeFromTyIdx(PointeeTyIdx)
->GetKind() == kTypeStructIncomplete) {
UnresolvedTypes.insert({PtrTy->getPointeeType()->getAsRecordDecl(), MTy});
}
TypeAttrs Attrs;
// Get alignment from the pointee type
if (unsigned int AlignmentBits =
Context->getTypeAlignIfKnown(PtrTy->getPointeeType())) {
if (AlignmentBits >
Context->getTypeUnadjustedAlign(PtrTy->getPointeeType())) {
Attrs.SetAlign(AlignmentBits / 8);
}
}
MTy->SetTypeAttrs(Attrs);
TypeMap.insert({PtrTy, MTy->GetTypeIndex()});
return MTy->GetTypeIndex();
} else if (const clang::ReferenceType *RefTy =
llvm::dyn_cast<clang::ReferenceType>(Ty)) {
TyIdx BaseTyIdx = type2MplIdx(RefTy->getPointeeType());
MIRType *MTy = GlobalTables::GetTypeTable().GetOrCreatePointerType(
BaseTyIdx, PointerPrimTy);
TypeMap.insert({PtrTy, MTy->GetTypeIndex()});
return MTy->GetTypeIndex();
} else if (const clang::ConstantArrayType *ArrTy =
llvm::dyn_cast<clang::ConstantArrayType>(Ty)) {
// Create a constant array type based on a known type
TyIdx BaseTyIdx = type2MplIdx(ArrTy->getElementType());
const llvm::APInt &APSize = ArrTy->getSize();
uint32_t Size = (uint32_t)APSize.getSExtValue();
std::vector<maple::uint32> SizeArray{Size};
MIRArrayType ArrayTy(BaseTyIdx, SizeArray);
MIRArrayType *MTy = static_cast<MIRArrayType *>(
GlobalTables::GetTypeTable().GetOrCreateMIRTypeNode(ArrayTy));
TypeAttrs Attrs = MTy->GetTypeAttrs();
// Get alignment from the element type
if (unsigned int AlignmentBits =
Context->getTypeAlignIfKnown(ArrTy->getElementType())) {
if (AlignmentBits >
Context->getTypeUnadjustedAlign(ArrTy->getElementType())) {
Attrs.SetAlign(AlignmentBits / 8);
}
}
MTy->SetTypeAttrs(Attrs);
TypeMap.insert({ArrTy, MTy->GetTypeIndex()});
return MTy->GetTypeIndex();
} else if (const clang::IncompleteArrayType *IncArrTy =
llvm::dyn_cast<clang::IncompleteArrayType>(Ty)) {
// For an incomplete array type, assume a length of 1
TyIdx BaseTyIdx = type2MplIdx(IncArrTy->getElementType());
std::vector<maple::uint32> SizeArray{1};
MIRArrayType ArrayTy(BaseTyIdx, SizeArray);
MIRArrayType *MTy = static_cast<MIRArrayType *>(
GlobalTables::GetTypeTable().GetOrCreateMIRTypeNode(ArrayTy));
TypeAttrs Attrs = MTy->GetTypeAttrs();
// Get alignment from the element type
if (unsigned int AlignmentBits =
Context->getTypeAlignIfKnown(IncArrTy->getElementType())) {
if (AlignmentBits >
Context->getTypeUnadjustedAlign(IncArrTy->getElementType())) {
Attrs.SetAlign(AlignmentBits / 8);
}
}
MTy->SetTypeAttrs(Attrs);
TypeMap.insert({IncArrTy, MTy->GetTypeIndex()});
return MTy->GetTypeIndex();
} else if (Ty->isRecordType()) {
// Handle an undefined struct
clang::RecordDecl *Record = Ty->getAsRecordDecl();
std::string TypeName = Record->getName().str();
MIRStructType Struct(kTypeStructIncomplete);
MIRType *MTy = GlobalTables::GetTypeTable().GetOrCreateMIRTypeNode(Struct);
GStrIdx StrIdx =
GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(TypeName);
MTy->SetNameStrIdx(StrIdx);
Module->GetTypeNameTab()->SetGStrIdxToTyIdx(StrIdx, MTy->GetTypeIndex());
Module->PushbackTypeDefOrder(StrIdx);
TypeMap.insert({Ty, MTy->GetTypeIndex()});
return MTy->GetTypeIndex();
} else if (Ty->isEnumeralType()) {
const clang::EnumType *EnumTy = llvm::dyn_cast<clang::EnumType>(Ty);
clang::QualType QT = EnumTy->getDecl()->getIntegerType();
return type2MplIdx(QT);
}
Ty->dump();
ASSERT(false, "Failed to convert type");
return TyIdx(0);
}
MIRType *Clang2MapleVisitor::type2Mpl(clang::QualType QT) {
return GlobalTables::GetTypeTable().GetTypeFromTyIdx(type2MplIdx(QT));
}
int Clang2MapleVisitor::fileID2Mpl(clang::FileID FID) {
auto it = FileMap.find(FID.getHashValue());
if (it != FileMap.end()) {
return it->second;
}
// If this FileID is not in the map, create it
const clang::FileEntry *File =
Context->getSourceManager().getFileEntryForID(FID);
std::string FileName;
if (File) {
FileName = File->getName().str().c_str();
} else {
FileName = "invalid_file";
}
GStrIdx StrIdx =
GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(FileName);
int Idx = FileIdx++;
Module->PushbackFileInfo(MIRInfoPair(StrIdx, Idx));
FileMap.insert({FID.getHashValue(), Idx});
return Idx;
}
MIRSymbol *Clang2MapleVisitor::decl2Mpl(const clang::Decl *D) {
auto it = DeclMap.find(D);
if (it != DeclMap.end()) {
return it->second;
}
// Check for use of an implicit decl. This shows up for builtins like
// `abort`.
if (D->isImplicit()) {
return Visit(D);
}
D->dump();
ASSERT(false, "Failed to find decl");
return nullptr;
}
SrcPosition Clang2MapleVisitor::sourceLocation2Mpl(clang::SourceLocation Loc) {
SrcPosition SrcPos;
if (!Loc.isValid()) {
return SrcPos;
}
clang::SourceManager &SM = Context->getSourceManager();
if (Loc.isFileID()) {
clang::PresumedLoc PLoc = SM.getPresumedLoc(Loc);
if (PLoc.isInvalid()) {
return SrcPos;
}
SrcPos.SetFileNum(fileID2Mpl(PLoc.getFileID()));
SrcPos.SetLineNum(PLoc.getLine());
SrcPos.SetColumn(PLoc.getColumn());
return SrcPos;
}
return sourceLocation2Mpl(SM.getExpansionLoc(Loc));
}
void Clang2MapleVisitor::addStmtToBlock(BlockNode *Block, StmtNode *SNode) {
// Merge block into this one
if (SNode->GetOpCode() == OP_block) {
BlockNode *InnerBlock = static_cast<BlockNode *>(SNode);
Block->AppendStatementsFromBlock(*InnerBlock);
} else {
Block->AddStatement(SNode);
}
}
void Clang2MapleVisitor::addToBlock(BlockNode *Block, Result &Res) {
for (Result::iterator It = Res.beginStmtsBefore(); It != Res.endStmtsBefore();
++It) {
Block->AddStatement(*It);
}
if (!Res.mayDrop()) {
if (StmtNode *SNode = getNodeAsStmt(Res)) {
addStmtToBlock(Block, SNode);
}
}
for (Result::iterator It = Res.beginStmtsAfter(); It != Res.endStmtsAfter();
++It) {
Block->AddStatement(*It);
}
}
BaseNode *Clang2MapleVisitor::exprToCond(BaseNode *Cond) {
if (kOpcodeInfo.IsCompare(Cond->op))
return Cond;
MIRType *IntTy =
GlobalTables::GetTypeTable().GetTypeFromTyIdx(TyIdx(PTY_i32));
MIRType *OpndTy =
GlobalTables::GetTypeTable().GetTypeFromTyIdx(TyIdx(Cond->GetPrimType()));
switch (Cond->GetPrimType()) {
case PTY_i8:
case PTY_i16:
case PTY_i32:
case PTY_i64:
case PTY_u8:
case PTY_u16:
case PTY_u32:
case PTY_u64:
case PTY_a32:
case PTY_a64:
case PTY_u1: {
ConstvalNode *Zero = Builder->CreateIntConst(0, Cond->GetPrimType());
return Builder->CreateExprCompare(OP_ne, *IntTy, *OpndTy, Cond, Zero);
}
case PTY_f32: {
ConstvalNode *Zero = Builder->CreateFloatConst(0.0f);
return Builder->CreateExprCompare(OP_ne, *IntTy, *OpndTy, Cond, Zero);
}
case PTY_f64: {
ConstvalNode *Zero = Builder->CreateDoubleConst(0.0);
return Builder->CreateExprCompare(OP_ne, *IntTy, *OpndTy, Cond, Zero);
}
case PTY_ptr: {
ConstvalNode *Zero = Builder->CreateIntConst(0, PointerPrimTy);
return Builder->CreateExprCompare(OP_ne, *IntTy, *OpndTy, Cond, Zero);
}
default:
LogInfo::MapleLogger() << "Warning: Unhandled type in exprToCond\n";
Cond->Dump();
return Cond;
}
}
static Opcode notCondOperator(Opcode op) {
switch (op) {
case OP_eq:
return OP_ne;
case OP_ge:
return OP_lt;
case OP_gt:
return OP_le;
case OP_le:
return OP_gt;
case OP_lt:
return OP_ge;
case OP_ne:
return OP_eq;
default:
LogInfo::MapleLogger() << "Operator: " << op << "\n";
ASSERT(false, "Unhandled type in notCondOperator");
}
}
BaseNode *Clang2MapleVisitor::exprToNotCond(BaseNode *Cond) {
if (kOpcodeInfo.IsCompare(Cond->op)) {
CompareNode *Compare = static_cast<CompareNode *>(Cond);
Compare->SetOpCode(notCondOperator(Compare->GetOpCode()));
return Cond;
}
MIRType *IntTy =
GlobalTables::GetTypeTable().GetTypeFromTyIdx(TyIdx(PTY_i32));
MIRType *OpndTy =
GlobalTables::GetTypeTable().GetTypeFromTyIdx(TyIdx(Cond->GetPrimType()));
switch (Cond->GetPrimType()) {
case PTY_i8:
case PTY_i16:
case PTY_i32:
case PTY_i64:
case PTY_u8:
case PTY_u16:
case PTY_u32:
case PTY_u64:
case PTY_a32:
case PTY_a64:
case PTY_u1: {
ConstvalNode *Zero = Builder->CreateIntConst(0, Cond->GetPrimType());
return Builder->CreateExprCompare(OP_eq, *IntTy, *OpndTy, Cond, Zero);
}
case PTY_f32: {
ConstvalNode *Zero = Builder->CreateFloatConst(0.0f);
return Builder->CreateExprCompare(OP_eq, *IntTy, *OpndTy, Cond, Zero);
}
case PTY_f64: {
ConstvalNode *Zero = Builder->CreateDoubleConst(0.0);
return Builder->CreateExprCompare(OP_eq, *IntTy, *OpndTy, Cond, Zero);
}
case PTY_ptr: {
ConstvalNode *Zero = Builder->CreateIntConst(0, PointerPrimTy);
return Builder->CreateExprCompare(OP_eq, *IntTy, *OpndTy, Cond, Zero);
}
default:
LogInfo::MapleLogger() << "Warning: Unhandled type in exprToCond\n";
Cond->Dump();
return Cond;
}
}
FieldID Clang2MapleVisitor::recordFieldIDs(const clang::RecordDecl *Record,
const clang::RecordDecl *Ancestor,
FieldID Base) {
FieldID CurrentField = Base;
for (const auto *I : Record->fields()) {
CurrentField++;
FieldMap[Ancestor][Base][I] = CurrentField;
const clang::Type *FieldType = I->getType().getTypePtr();
if (FieldType->isRecordType()) {
CurrentField +=
recordFieldIDs(FieldType->getAsRecordDecl(), Ancestor, CurrentField);
}
}
return CurrentField - Base; // Number of fields
}
BaseNode *Clang2MapleVisitor::getNodeAsLVal(Result &Res) {
if (Res.isDeref()) {
// Do not dereference arrays
if (Res.getValueTy()->GetKind() == kTypeArray && Res.getField() == 0) {
return Res.getAddr();
}
return Builder->CreateExprIaddrof(*Res.getValueTy(), *Res.getAddrTy(),
Res.getField(), Res.getAddr());
}
return getNodeAsRVal(Res);
}
BaseNode *Clang2MapleVisitor::getNodeAsRVal(Result &Res) {
BaseNode *N = Res.getNode();
if (N) {
if (Res.isDeref()) {
// Do not dereference arrays
if (Res.getValueTy()->GetKind() == kTypeArray && Res.getField() == 0) {
return Res.getAddr();
}
// Do not dereference functions
if (Res.getValueTy()->GetKind() == kTypeFunction) {
return Res.getAddr();
}
return Builder->CreateExprIread(*Res.getValueTy(), *Res.getAddrTy(),
Res.getField(), Res.getAddr());
}
// If a call is used as an rvalue, we need to create a temporary to assign
// the return value to, then read from that for the rvalue.
Opcode Op = N->GetOpCode();
if (kOpcodeInfo.IsCall(Op)) {
MIRType *RetValTy = Res.getValueTy();
// If there is a field access, then we need to create a temp for the
// struct, then get the field.
if (Res.getField()) {
RetValTy = type2Mpl(Context->getRecordType(Res.getBaseRecordDecl()));
}
// Generate a temp for result of the function, then read that as the
// rval
MIRSymbol *Sym = Builder->GetOrCreateLocalDecl(
"_result" + std::to_string(Res.getLoc().getRawEncoding()), *RetValTy);
StmtNode *TmpAssign = nullptr;
if (Op == OP_call) {
CallNode *Call = static_cast<CallNode *>(N);
// If the return type is a structure too big to fit in registers, then
// pass the address of the return value as an implicit first parameter
// to the function.
MapleVector<BaseNode *> &Args = Call->GetNopnd();
if (RetValTy->GetSize() > 16) {
BaseNode *AddrOf = Builder->CreateExprAddrof(0, *Sym);
AddrOf->SetPrimType(PointerPrimTy);
Args.insert(Args.begin(), AddrOf);
Call->SetNumOpnds(Args.size());
TmpAssign = Call;
} else {
TmpAssign = Builder->CreateStmtCallAssigned(
Call->GetPUIdx(), Call->GetNopnd(), Sym, OP_callassigned);
}
} else if (Op == OP_icall) {
IcallNode *Call = static_cast<IcallNode *>(N);
// If the return type is a structure too big to fit in registers, then
// pass the address of the return value as an implicit first parameter
// to the function.
MapleVector<BaseNode *> &Args = Call->GetNopnd();
if (RetValTy->GetSize() > 16) {
BaseNode *AddrOf = Builder->CreateExprAddrof(0, *Sym);
AddrOf->SetPrimType(PointerPrimTy);
Args.insert(Args.begin() + 1, AddrOf);
Call->SetNumOpnds(Args.size());
TmpAssign = Call;
} else {
TmpAssign = Builder->CreateStmtIcallAssigned(Call->GetNopnd(), *Sym);
}
} else if (Op == OP_intrinsiccall) {
IntrinsiccallNode *Call = static_cast<IntrinsiccallNode *>(N);
// If the return type is a structure too big to fit in registers, then
// pass the address of the return value as an implicit first parameter
// to the function.
MapleVector<BaseNode *> &Args = Call->GetNopnd();
if (RetValTy->GetSize() > 16) {
BaseNode *AddrOf = Builder->CreateExprAddrof(0, *Sym);
AddrOf->SetPrimType(PointerPrimTy);
Args.insert(Args.begin(), AddrOf);
Call->SetNumOpnds(Args.size());
TmpAssign = Call;
} else {
TmpAssign = Builder->CreateStmtIntrinsicCallAssigned(
Call->GetIntrinsic(), Call->GetNopnd(), Sym,
Res.getValueTy()->GetTypeIndex());
}
} else {
LogInfo::MapleLogger() << "Unhandled call node in getNodeAsRVal:\n";
N->Dump();
}
TmpAssign->SetSrcPos(sourceLocation2Mpl(Res.getLoc()));
Res.appendStmtBefore(TmpAssign);
// If a struct is returned, the later passes need an assignment, other
// than the callassigned, to properly retrieve the struct.
if (RetValTy->IsStructType()) {
MIRSymbol *StructSym = Builder->GetOrCreateLocalDecl(
"_resultStruct" + std::to_string(Res.getLoc().getRawEncoding()),
*RetValTy);
TmpAssign = Builder->CreateStmtDassign(
*StructSym, 0, Builder->CreateExprDread(*RetValTy, 0, *Sym));
TmpAssign->SetSrcPos(sourceLocation2Mpl(Res.getLoc()));
Res.appendStmtBefore(TmpAssign);
Sym = StructSym;
}
return Builder->CreateExprDread(*Res.getValueTy(), Res.getField(), *Sym);
} else if (isAssign(Op)) {
// If the RHS of an assignment is another assignment, then we need to
// emit that assignment statement first, then use the LHS of that
// assignment as the operand.
StmtNode *SNode = static_cast<StmtNode *>(N);
SNode->SetSrcPos(sourceLocation2Mpl(Res.getLoc()));
Res.appendStmtBefore(SNode);
if (Op == OP_dassign) {
DassignNode *Assign = static_cast<DassignNode *>(N);
return Builder->GetCurrentFuncCodeMp()->New<AddrofNode>(
OP_dread, Assign->GetRHS()->GetPrimType(), Assign->GetStIdx(),
Assign->GetFieldID());
} else if (Op == OP_iassign) {
IassignNode *Assign = static_cast<IassignNode *>(N);
MIRPtrType *PtrTy = static_cast<MIRPtrType *>(
GlobalTables::GetTypeTable().GetTypeFromTyIdx(Assign->GetTyIdx()));
BaseNode *Addr = Assign->Opnd(0);
MIRType *Ty = PtrTy->GetPointedType();
return Builder->CreateExprIread(*Ty, *PtrTy, Assign->GetFieldID(),
Addr);
} else if (kOpcodeInfo.IsCallAssigned(Op)) {
if (Op == OP_callassigned) {
CallNode *Assign = static_cast<CallNode *>(N);
CallReturnPair Ret = Assign->GetReturnPair(0);
return Builder->GetCurrentFuncCodeMp()->New<AddrofNode>(
OP_dread, Assign->GetCallReturnType()->GetPrimType(), Ret.first,
Ret.second.GetFieldID());
} else if (Op == OP_icallassigned) {
IcallNode *Assign = static_cast<IcallNode *>(N);
CallReturnPair Ret = Assign->GetReturnVec()[0];
return Builder->GetCurrentFuncCodeMp()->New<AddrofNode>(
OP_dread, Assign->GetCallReturnType()->GetPrimType(), Ret.first,
Ret.second.GetFieldID());
} else {
LogInfo::MapleLogger()
<< "Unhandled call-assign node in getNodeAsRVal:\n";
N->Dump();
}
}
}
return N;
} else if (Res.isSym()) {
MIRSymbol *Sym = Res.getSym();
if (Sym->GetSKind() == kStFunc) {
MIRFunction *Func = Sym->GetFunction();
BaseNode *AddrOf = Builder->CreateExprAddroffunc(Func->GetPuidx());
AddrOf->SetPrimType(PointerPrimTy);
return AddrOf;
}
return Builder->CreateExprDread(*Res.getValueTy(), Res.getField(), *Sym);
}
return nullptr;
}
StmtNode *Clang2MapleVisitor::getNodeAsStmt(Result &Res) {
BaseNode *N = Res.getNode();
if (Res.isDeref()) {
// Do not dereference arrays
if (Res.getValueTy()->GetKind() == kTypeArray) {
N = Res.getAddr();
} else {
N = Builder->CreateExprIread(*Res.getValueTy(), *Res.getAddrTy(),
Res.getField(), Res.getAddr());
}
} else if (Res.isSym()) {
MIRSymbol *Sym = Res.getSym();
if (Sym->GetSKind() == kStFunc) {
MIRFunction *Func = Sym->GetFunction();
N = Builder->CreateExprAddroffunc(Func->GetPuidx());
N->SetPrimType(PointerPrimTy);
} else {
N = Builder->CreateExprDread(*Res.getValueTy(), Res.getField(), *Sym);
}
}
StmtNode *SNode = nullptr;
if (N) {
Opcode Op = N->GetOpCode();
// If this is a call with a return type which must be passed by reference,
// generate a temp and pass its address as an implicit first parameter.
if (kOpcodeInfo.IsCall(Op)) {
MIRType *RetValTy = Res.getValueTy();
// If there is a field access, then we need to create a temp for the
// struct, then get the field.
if (Res.getField()) {
RetValTy = type2Mpl(Context->getRecordType(Res.getBaseRecordDecl()));
}
if (RetValTy->GetSize() > 16) {
// Generate a temp for result of the function
MIRSymbol *Sym = Builder->GetOrCreateLocalDecl(
"_result" + std::to_string(Res.getLoc().getRawEncoding()),
*RetValTy);
StmtNode *TmpAssign = nullptr;
if (Op == OP_call) {
CallNode *Call = static_cast<CallNode *>(N);
MapleVector<BaseNode *> &Args = Call->GetNopnd();
BaseNode *AddrOf = Builder->CreateExprAddrof(0, *Sym);
AddrOf->SetPrimType(PointerPrimTy);
Args.insert(Args.begin(), AddrOf);
Call->SetNumOpnds(Args.size());
} else if (Op == OP_icall) {
IcallNode *Call = static_cast<IcallNode *>(N);
MapleVector<BaseNode *> &Args = Call->GetNopnd();
BaseNode *AddrOf = Builder->CreateExprAddrof(0, *Sym);
AddrOf->SetPrimType(PointerPrimTy);
Args.insert(Args.begin() + 1, AddrOf);
Call->SetNumOpnds(Args.size());
} else if (Op == OP_intrinsiccall) {
IntrinsiccallNode *Call = static_cast<IntrinsiccallNode *>(N);
MapleVector<BaseNode *> &Args = Call->GetNopnd();
BaseNode *AddrOf = Builder->CreateExprAddrof(0, *Sym);
AddrOf->SetPrimType(PointerPrimTy);
Args.insert(Args.begin(), AddrOf);
Call->SetNumOpnds(Args.size());
} else {
LogInfo::MapleLogger() << "Unhandled call node in getNodeAsRVal:\n";
N->Dump();
}
}
SNode = static_cast<StmtNode *>(N);
} else if (kOpcodeInfo.IsStmt(Op)) {
SNode = static_cast<StmtNode *>(N);
} else {
// If the node is an expression, not a statement, wrap it in an eval
SNode = Builder->CreateStmtUnary(OP_eval, N);
}
}
SNode->SetSrcPos(sourceLocation2Mpl(Res.getLoc()));
return SNode;
}
void Clang2MapleVisitor::appendResultBefore(Result &To, Result R) {
for (Result::iterator It = R.beginStmtsBefore(); It != R.endStmtsBefore();
++It) {
To.appendStmtBefore(*It);
}
if (!R.mayDrop()) {
if (StmtNode *SNode = getNodeAsStmt(R)) {
To.appendStmtBefore(SNode);
}
}
for (Result::iterator It = R.beginStmtsAfter(); It != R.endStmtsAfter();
++It) {
To.appendStmtBefore(*It);
}
}
bool Clang2MapleVisitor::evaluateNodeAsInt(int64_t &Result, const BaseNode *N) {
if (N->GetOpCode() == OP_constval) {
const ConstvalNode *ConstNode = static_cast<const ConstvalNode *>(N);
const MIRConst *Const = ConstNode->GetConstVal();
if (Const->GetKind() == kConstInt) {
const MIRIntConst *IntConst = static_cast<const MIRIntConst *>(Const);
Result = IntConst->GetValue();
return true;
}
}
return false;
}
MIRConst *Clang2MapleVisitor::evaluateExprAsConst(const clang::Expr *E,
MIRType *Ty) {
clang::Expr::EvalResult InitConstResult;
if (E->EvaluateAsConstantExpr(InitConstResult,
clang::Expr::EvaluateForCodeGen, *Context)) {
clang::APValue InitConstVal = InitConstResult.Val;
if (InitConstVal.isInt()) {
llvm::APSInt IntVal = InitConstVal.getInt();
MIRConst *IntConst = GlobalTables::GetIntConstTable().GetOrCreateIntConst(
IntVal.getExtValue(), *Ty);
return IntConst;
} else if (InitConstVal.isFloat()) {
MIRConst *FloatConst = nullptr;
llvm::APFloat FloatVal = InitConstVal.getFloat();
if (&FloatVal.getSemantics() == &llvm::APFloat::IEEEsingle()) {
FloatConst = Builder->GetCurrentFuncDataMp()->New<MIRFloatConst>(
FloatVal.convertToFloat(),
*GlobalTables::GetTypeTable().GetPrimType(PTY_f32));
} else if (&FloatVal.getSemantics() == &llvm::APFloat::IEEEdouble()) {
FloatConst = Builder->GetCurrentFuncDataMp()->New<MIRDoubleConst>(
FloatVal.convertToDouble(),
*GlobalTables::GetTypeTable().GetPrimType(PTY_f64));
} else if (&FloatVal.getSemantics() == &llvm::APFloat::IEEEquad()) {
bool LosesInfo;
FloatVal.convert(llvm::APFloat::IEEEdouble(),
llvm::APFloatBase::roundingMode::rmNearestTiesToAway,
&LosesInfo);
FloatConst = Builder->GetCurrentFuncDataMp()->New<MIRDoubleConst>(
FloatVal.convertToDouble(),
*GlobalTables::GetTypeTable().GetPrimType(PTY_f64));
} else {
LogInfo::MapleLogger()
<< "Unexpected type of floating literal: " << Ty->GetPrimType()
<< "\n";
}
return FloatConst;
}
}
return nullptr;
}
MIRConst *Clang2MapleVisitor::createZero(MIRType *Ty) {
PrimType PTy = Ty->GetPrimType();
if (PrimitiveType(PTy).IsAddress()) {
return GlobalTables::GetIntConstTable().GetOrCreateIntConst(0,
*IntPointerTy);
} else if (PrimitiveType(PTy).IsInteger()) {
return GlobalTables::GetIntConstTable().GetOrCreateIntConst(0, *Ty);
} else if (PTy == PTY_f32) {
return Builder->GetCurrentFuncDataMp()->New<MIRFloatConst>(0.0f, *Ty);
} else if (PTy == PTY_f64) {
return Builder->GetCurrentFuncDataMp()->New<MIRDoubleConst>(0.0, *Ty);
} else if (Ty->IsStructType()) {
MIRStructType *StructTy = static_cast<MIRStructType *>(Ty);
MIRAggConst *Agg =
Builder->GetCurrentFuncDataMp()->New<MIRAggConst>(*Module, *Ty);
for (size_t Field = 0; Field < StructTy->GetFieldsSize(); Field++) {
MIRType *FieldTy = StructTy->GetElemType(Field);
MIRConst *Zero = createZero(FieldTy);
Agg->AddItem(Zero, Field + 1);
}
return Agg;
} else if (Ty->GetKind() == kTypeArray) {
MIRArrayType *ArrTy = static_cast<MIRArrayType *>(Ty);
MIRAggConst *Agg =
Builder->GetCurrentFuncDataMp()->New<MIRAggConst>(*Module, *Ty);
MIRConst *Zero = createZero(ArrTy->GetElemType());
for (size_t i = 0; i < ArrTy->GetSizeArrayItem(0); i++) {
Agg->PushBack(Zero);
}
return Agg;
}
LogInfo::MapleLogger() << "Error: createZero does not yet handle PrimType "
<< PTy << "\n";
return nullptr;
}
Result
Clang2MapleVisitor::buildExprToComputeSizeFromVLA(clang::SourceLocation Loc,
const clang::QualType &QT) {
Result Res(Loc);
const clang::Type *Ty = QT.getCanonicalType().getTypePtrOrNull();
MIRType *SizeTy = type2Mpl(Context->getSizeType());
MIR_ASSERT(!Ty->isArrayType() ||
(Ty->isConstantArrayType() || Ty->isVariableArrayType()));
if (Ty->isArrayType()) {
BaseNode *LHS = nullptr, *RHS = nullptr;
Result ResLHS = buildExprToComputeSizeFromVLA(
Loc, llvm::dyn_cast<clang::ArrayType>(Ty)->getElementType());
Res.appendStmts(ResLHS);
LHS = getNodeAsRVal(ResLHS);
if (Ty->isVariableArrayType()) {
clang::Expr *Size =
llvm::dyn_cast<clang::VariableArrayType>(Ty)->getSizeExpr();
Result ResRHS = Visit(Size);
Res.appendStmts(ResRHS);
RHS = getNodeAsRVal(ResRHS);
MIR_ASSERT(Size->getType()->isIntegerType());
if (!Size->getType()->hasUnsignedIntegerRepresentation()) {
RHS = Builder->CreateExprTypeCvt(OP_cvt, SizeTy->GetPrimType(),
RHS->GetPrimType(), *RHS);
}
} else {
llvm::APInt Size =
llvm::dyn_cast<clang::ConstantArrayType>(Ty)->getSize();
RHS = Builder->CreateIntConst(Size.getSExtValue(),
IntPointerTy->GetPrimType());
}
Res.setNode(Builder->CreateExprBinary(OP_mul, *SizeTy, LHS, RHS), SizeTy);
} else {
MIRType *MTy = type2Mpl(QT);
Res.setNode(Builder->CreateIntConst(MTy->GetSize(), SizeTy->GetPrimType()),
SizeTy);
}
return Res;
}
BaseNode *Clang2MapleVisitor::constToNode(MIRConst *Const) {
// Maple cannot handle an addrof node with an offset. Expand it into an
// addition.
if (Const->GetKind() == kConstAddrof) {
MIRAddrofConst *AddrOf = static_cast<MIRAddrofConst *>(Const);
if (AddrOf->GetOffset()) {
BaseNode *Offset =
Builder->CreateIntConst(AddrOf->GetOffset(), PointerPrimTy);
BaseNode *Addr = Builder->CreateExprAddrof(AddrOf->GetFieldID(),
AddrOf->GetSymbolIndex());
Addr->SetPrimType(PointerPrimTy);
return Builder->CreateExprBinary(OP_add, Const->GetType(), Addr, Offset);
} else {
BaseNode *Node = Builder->CreateExprAddrof(AddrOf->GetFieldID(),
AddrOf->GetSymbolIndex());
Node->SetPrimType(PointerPrimTy);
return Node;
}
} else if (Const->GetKind() == kConstAddrofFunc) {
MIRAddroffuncConst *AOFConst = static_cast<MIRAddroffuncConst *>(Const);
BaseNode *AddrOf = Builder->CreateExprAddroffunc(AOFConst->GetValue());
AddrOf->SetPrimType(PointerPrimTy);
return AddrOf;
} else if (Const->GetKind() == kConstLblConst) {
MIRLblConst *LabelConst = static_cast<MIRLblConst *>(Const);
AddroflabelNode *AOL =
Builder->GetCurrentFuncCodeMp()->New<AddroflabelNode>(
LabelConst->GetValue());
AOL->SetPrimType(PointerPrimTy);
return AOL;
} else if (Const->GetKind() == kConstStrConst) {
MIRStrConst *StrConst = static_cast<MIRStrConst *>(Const);
return Builder->GetCurrentFuncCodeMp()->New<ConststrNode>(
PointerPrimTy, StrConst->GetValue());
}
return Builder->CreateConstval(Const);
}
unsigned Clang2MapleVisitor::assignStruct(Result &Res, MIRSymbol *BaseSym,
BaseNode *BaseAddr,
MIRStructType *StructTy,
BaseNode *Src, FieldID Base) {
MIRType *StructPtrTy = GlobalTables::GetTypeTable().GetOrCreatePointerType(
*StructTy, PointerPrimTy);
SrcPosition Pos = sourceLocation2Mpl(Res.getLoc());
if (Src->op == OP_constval) { // constant initializers
ConstvalNode *ConstNode = static_cast<ConstvalNode *>(Src);
MIRConst *Const = ConstNode->GetConstVal();
ASSERT(Const->GetKind() == kConstAggConst,
"Expected agg constant in struct initializer\n");
MIRAggConst *Agg = static_cast<MIRAggConst *>(Const);
unsigned Size = Agg->GetConstVec().size();
for (unsigned i = 0; i < Size; i++) {
MIRConst *FieldConst = Agg->GetConstVecItem(i);
MIRType *FieldTy = &FieldConst->GetType();
FieldID Field = Base + Agg->GetFieldIdItem(i);
if (FieldTy->GetKind() == kTypeScalar ||
FieldTy->GetKind() == kTypePointer ||
FieldTy->GetKind() == kTypeBitField) {
BaseNode *FieldNode = constToNode(FieldConst);
StmtNode *FieldAssign;
if (BaseSym) {
FieldAssign = Builder->CreateStmtDassign(*BaseSym, Field, FieldNode);
} else {
FieldAssign = Builder->CreateStmtIassign(
*StructPtrTy, Field,
BaseAddr->CloneTree(*Builder->GetCurrentFuncCodeMpAllocator()),
FieldNode);
}
FieldAssign->SetSrcPos(Pos);
Res.appendStmtBefore(FieldAssign);
} else {
ConstvalNode FieldNode(FieldConst);
if (FieldTy->IsStructType()) {
assignStruct(Res, BaseSym, BaseAddr, StructTy, &FieldNode, Field);
} else if (FieldTy->GetKind() == kTypeArray) {
BaseNode *ElemBaseAddr = getBase(BaseSym, BaseAddr, Base);
MIRArrayType *ArrayTy = static_cast<MIRArrayType *>(FieldTy);
if (ElemBaseAddr->GetOpCode() == OP_iread ||
ElemBaseAddr->GetOpCode() == OP_iaddrof) {
IreadNode *IRead = static_cast<IreadNode *>(ElemBaseAddr);
IRead->SetFieldID(Field);
} else if (ElemBaseAddr->GetOpCode() == OP_addrof ||
ElemBaseAddr->GetOpCode() == OP_dread) {
AddrofNode *AddrOf = static_cast<AddrofNode *>(ElemBaseAddr);
AddrOf->SetFieldID(Field);
} else {
ElemBaseAddr->Dump();
ASSERT(false, "Unexpected base address in assignStruct");
}
assignArray(Res, ElemBaseAddr, ArrayTy, &FieldNode);
} else {
FieldConst->Dump(nullptr);
LogInfo::MapleLogger() << "\n";
FieldTy->Dump(0, false);
ASSERT(false, "Error: field is not a scalar, struct, or array\n");
}
}
}
return Size + 1;
} else if (Src->GetOpCode() ==
OP_intrinsicopwithtype) { // non-constant initializers
IntrinsicopNode *N = static_cast<IntrinsicopNode *>(Src);
unsigned Size = N->NumOpnds();
for (unsigned i = 0; i < Size; i++) {
IreadNode *WrapperNode = static_cast<IreadNode *>(N->Opnd(i));
BaseNode *FieldNode = WrapperNode->Opnd(0);
FieldID Field = Base + WrapperNode->GetFieldID();
if (FieldNode->GetPrimType() == PTY_agg &&
(FieldNode->GetOpCode() == OP_intrinsicopwithtype ||
FieldNode->GetOpCode() == OP_constval)) {
MIRType *FieldTy;
if (FieldNode->GetOpCode() == OP_intrinsicopwithtype) {
IntrinsicopNode *NField = static_cast<IntrinsicopNode *>(FieldNode);
FieldTy =
GlobalTables::GetTypeTable().GetTypeFromTyIdx(NField->GetTyIdx());
} else { // FieldNode->GetOpCode() == OP_constval
ConstvalNode *ConstNode = static_cast<ConstvalNode *>(FieldNode);
MIRConst *Const = ConstNode->GetConstVal();
FieldTy = &Const->GetType();
}
if (FieldTy->GetKind() == kTypeArray) {
BaseNode *ElemBaseAddr = getBase(BaseSym, BaseAddr, Base);
MIRArrayType *ArrayTy = static_cast<MIRArrayType *>(FieldTy);
if (ElemBaseAddr->GetOpCode() == OP_iread ||
ElemBaseAddr->GetOpCode() == OP_iaddrof) {
IreadNode *IRead = static_cast<IreadNode *>(ElemBaseAddr);
IRead->SetFieldID(Field);
} else if (ElemBaseAddr->GetOpCode() == OP_addrof ||
ElemBaseAddr->GetOpCode() == OP_dread) {
AddrofNode *AddrOf = static_cast<AddrofNode *>(ElemBaseAddr);
AddrOf->SetFieldID(Field);
} else {
ElemBaseAddr->Dump();
ASSERT(false, "Unexpected base address in assignStruct");
}
assignArray(Res, ElemBaseAddr, ArrayTy, FieldNode);
} else {
assignStruct(Res, BaseSym, BaseAddr, StructTy, FieldNode, Field);
}
} else {
StmtNode *FieldAssign;
if (BaseSym) {
FieldAssign = Builder->CreateStmtDassign(*BaseSym, Field, FieldNode);
} else {
FieldAssign = Builder->CreateStmtIassign(*StructPtrTy, Field,
BaseAddr, FieldNode);
}
FieldAssign->SetSrcPos(Pos);
Res.appendStmtBefore(FieldAssign);
}
}
return Size + 1;
} else { // Direct assignment of the structure
StmtNode *Assign;
if (BaseSym) {
Assign = Builder->CreateStmtDassign(*BaseSym, Base, Src);
} else {
Assign = Builder->CreateStmtIassign(*StructPtrTy, 0, BaseAddr, Src);
}
Assign->SetSrcPos(Pos);
Res.appendStmtBefore(Assign);
return StructTy->GetSize();
}
}
BaseNode *Clang2MapleVisitor::getBase(MIRSymbol *Sym, BaseNode *Base,
FieldID Field) {
ASSERT(Sym || Base, "getBase requires weither Sym or Base to be set");
if (Sym) {
BaseNode *AddrOf = Builder->CreateExprAddrof(Field, *Sym);
AddrOf->SetPrimType(PointerPrimTy);
return AddrOf;
} else {
return Base->CloneTree(*Builder->GetCurrentFuncCodeMpAllocator());
}
}
bool Clang2MapleVisitor::computeArrayOffset(size_t &Offset, ArrayNode *Array) {
Offset = 0;
MIRType *ElemTy = Array->GetArrayType(GlobalTables::GetTypeTable());
for (int i = 1, end = Array->NumOpnds(); i < end; i++) {
ASSERT(ElemTy->GetKind() == kTypeArray,
"Invalid indexing of non-array type");
MIRArrayType *ArrTy = static_cast<MIRArrayType *>(ElemTy);
ElemTy = ArrTy->GetElemType();
BaseNode *IndexNode = Array->GetNopndAt(i);
int64_t Val;
if (!evaluateNodeAsInt(Val, IndexNode)) {
return false;
}
Offset += Val * ElemTy->GetSize();
}
return true;
}
BaseNode *Clang2MapleVisitor::getAddrOfNode(BaseNode *N) {
switch (N->GetOpCode()) {
case OP_dread:
N->SetOpCode(OP_addrof);
N->SetPrimType(PointerPrimTy);
return N;
case OP_iread:
N->SetOpCode(OP_iaddrof);
N->SetPrimType(PointerPrimTy);
return N;
default:
ASSERT(false, "Unsupported node in addrOfNode");
}
}
unsigned Clang2MapleVisitor::assignArray(Result &Res, BaseNode *BaseAddr,
MIRArrayType *ArrayTy, BaseNode *Src) {
MIRType *ElemTy = ArrayTy->GetElemType();
size_t ElemSize = ElemTy->GetSize();
MIRType *PtrTy = GlobalTables::GetTypeTable().GetOrCreatePointerType(
*ElemTy, PointerPrimTy);
SrcPosition Pos = sourceLocation2Mpl(Res.getLoc());
size_t SizeInited = 0;
if (Src->op == OP_constval) { // constant initializers
ConstvalNode *ConstNode = static_cast<ConstvalNode *>(Src);
MIRConst *Const = ConstNode->GetConstVal();
if (Const->GetKind() == kConstAggConst) {
MIRAggConst *Agg = static_cast<MIRAggConst *>(Const);
for (unsigned ElemID = 0; ElemID < Agg->GetConstVec().size(); ++ElemID) {
BaseNode *IndexNode =
Builder->CreateIntConst(ElemID, IntPointerTy->GetPrimType());
ArrayNode *Array =
Builder->CreateExprArray(*ArrayTy, BaseAddr, IndexNode);
Array->SetBoundsCheck(false);
Array->SetPrimType(PointerPrimTy);
MIRConst *ElemConst = Agg->GetConstVecItem(ElemID);
if (ElemTy->GetKind() == kTypeArray) {
MIRArrayType *ElemArrayTy = static_cast<MIRArrayType *>(ElemTy);
ConstvalNode Elem(ElemConst);
SizeInited += assignArray(Res, Array, ElemArrayTy, &Elem);
} else if (ElemTy->GetKind() == kTypeStruct ||
ElemTy->GetKind() == kTypeUnion) {
MIRStructType *ElemStructTy = static_cast<MIRStructType *>(ElemTy);
MIRType *StructPtrTy =
GlobalTables::GetTypeTable().GetOrCreatePointerType(
*ElemStructTy, PointerPrimTy);
ConstvalNode Elem(ElemConst);
BaseNode *StructBase =
Builder->CreateExprIaddrof(*StructPtrTy, *StructPtrTy, 0, Array);
assignStruct(Res, nullptr, StructBase, ElemStructTy, &Elem);
SizeInited += ElemStructTy->GetSize();
} else {
BaseNode *Elem = constToNode(ElemConst);
IassignNode *ElemAssign =
Builder->CreateStmtIassign(*PtrTy, 0, Array, Elem);
ElemAssign->SetSrcPos(Pos);
Res.appendStmtBefore(ElemAssign);
SizeInited += ElemSize;
}
}
}
} else if (Src->op == OP_conststr) {
// Generate a memcpy to copy the string literal into the local variable
ConststrNode *ConstStr = static_cast<ConststrNode *>(Src);
UStrIdx SIdx = ConstStr->GetStrIdx();
std::string Str = GlobalTables::GetUStrTable().GetStringFromStrIdx(SIdx);
MapleVector<BaseNode *> MemcpyArgs(
Builder->GetCurrentFuncCodeMpAllocator()->Adapter());
MemcpyArgs.push_back(BaseAddr);
MemcpyArgs.push_back(ConstStr);
MemcpyArgs.push_back(Builder->GetConstInt(Str.size() + 1));
StmtNode *MemcpyCall =
Builder->CreateStmtIntrinsicCall(INTRN_C_memcpy, MemcpyArgs);
MemcpyCall->SetSrcPos(Pos);
Res.appendStmtBefore(MemcpyCall);
SizeInited = Str.size() + 1;
} else if (Src->op == OP_intrinsicopwithtype) { // non-constant initializers
NaryNode *N = static_cast<NaryNode *>(Src);
for (size_t ElemID = 0; ElemID < N->NumOpnds(); ++ElemID) {
BaseNode *IndexNode =
Builder->CreateIntConst(ElemID, IntPointerTy->GetPrimType());
ArrayNode *Array =
Builder->CreateExprArray(*ArrayTy, BaseAddr, IndexNode);
Array->SetBoundsCheck(false);
Array->SetPrimType(PointerPrimTy);
if (ElemTy->GetKind() == kTypeArray) {
MIRArrayType *ElemArrayTy = static_cast<MIRArrayType *>(ElemTy);
SizeInited += assignArray(Res, Array, ElemArrayTy, N->Opnd(ElemID));
} else if (ElemTy->GetKind() == kTypeStruct ||
ElemTy->GetKind() == kTypeUnion) {
MIRStructType *ElemStructTy = static_cast<MIRStructType *>(ElemTy);
MIRType *StructPtrTy =
GlobalTables::GetTypeTable().GetOrCreatePointerType(*ElemStructTy,
PointerPrimTy);
BaseNode *StructBase =
Builder->CreateExprIaddrof(*StructPtrTy, *StructPtrTy, 0, Array);
assignStruct(Res, nullptr, StructBase, ElemStructTy, N->Opnd(ElemID));
SizeInited += ElemStructTy->GetSize();
} else {
IassignNode *ElemAssign =
Builder->CreateStmtIassign(*PtrTy, 0, Array, N->Opnd(ElemID));
ElemAssign->SetSrcPos(Pos);
Res.appendStmtBefore(ElemAssign);
SizeInited += ElemSize;
}
}
} else {
LogInfo::MapleLogger()
<< "Warning: Unhandled aggregate initializer in assignArray\n";
Src->Dump();
}
// Fill in uninitialized elements with 0 using memset
if (SizeInited < ArrayTy->GetSize()) {
MapleVector<BaseNode *> MemsetArgs(
Builder->GetCurrentFuncCodeMpAllocator()->Adapter());
BaseNode *Offset = Builder->CreateIntConst(SizeInited, PointerPrimTy);
BaseNode *Base =
Builder->CreateExprBinary(OP_add, *IntPointerTy, BaseAddr, Offset);
MemsetArgs.push_back(Base);
BaseNode *Zero = Builder->CreateIntConst(0, PTY_i32);
MemsetArgs.push_back(Zero);
BaseNode *SizeLeft = Builder->CreateIntConst(
ArrayTy->GetSize() - SizeInited, IntPointerTy->GetPrimType());
MemsetArgs.push_back(SizeLeft);
StmtNode *MemsetCall =
Builder->CreateStmtIntrinsicCall(INTRN_C_memset, MemsetArgs);
MemsetCall->SetSrcPos(Pos);
Res.appendStmtBefore(MemsetCall);
}
return ArrayTy->GetSize();
}
// TODO: This function has a lot of duplication and may miss some possible
// combinations. It should be improved, possibly using some recursion to
// evaluate sub-expressions.
MIRConst *Clang2MapleVisitor::getInitializer(MIRType *Ty,
const clang::Expr *InitExpr) {
Result InitRes = Visit(InitExpr);
BaseNode *InitNode = getNodeAsRVal(InitRes);
// This case should only happen with an array of size 0
if (!InitNode) {
return nullptr;
}
if (InitNode->op == OP_constval) {
ConstvalNode *ConstNode = static_cast<ConstvalNode *>(InitNode);
// For array types, if there are less initializers than elements of the
// array, we need to fill in the rest.
MIRConst *Const = ConstNode->GetConstVal();
if (Ty->GetKind() == kTypeArray) {
MIRArrayType *ArrTy = static_cast<MIRArrayType *>(Ty);
if (Const->GetKind() == kConstAggConst) {
MIRAggConst *Agg = static_cast<MIRAggConst *>(Const);
completeArrayInitializer(Agg, ArrTy);
}
}
// For bitfields, assign the corresponding bitfield types to the
// initializers.
if (Ty->IsMIRStructType() && Const->GetKind() == kConstAggConst) {
MIRStructType *StructTy = static_cast<MIRStructType *>(Ty);
MIRAggConst *Agg = static_cast<MIRAggConst *>(Const);
for (unsigned Item = 0; Item < Agg->GetConstVec().size(); Item++) {
MIRType *FieldTy = StructTy->GetElemType(Item);
if (FieldTy->GetKind() == kTypeBitField) {
MIRConst *FieldConst = Agg->GetConstVecItem(Item);
ASSERT(FieldConst->GetKind() == kConstInt,
"bitfield initializer must be an integer");
MIRIntConst *FieldInit = static_cast<MIRIntConst *>(FieldConst);
Agg->SetItem(Item,
GlobalTables::GetIntConstTable().GetOrCreateIntConst(
FieldInit->GetValue(), *FieldTy),
Agg->GetFieldIdItem(Item));
}
}
}
return Const;
} else if (InitNode->op == OP_conststr) {
ConststrNode *ConstStr = static_cast<ConststrNode *>(InitNode);
UStrIdx SIdx = ConstStr->GetStrIdx();
if (Ty->GetKind() == kTypeArray) {
MIRArrayType *ArrTy = static_cast<MIRArrayType *>(Ty);
// Expand the string to an array of characters
std::string Str = GlobalTables::GetUStrTable().GetStringFromStrIdx(SIdx);
MIRAggConst *Agg =
Builder->GetCurrentFuncCodeMp()->New<MIRAggConst>(*Module, *Ty);
int Remaining = ArrTy->GetSizeArrayItem(0);
for (char &C : Str) {
Agg->PushBack(GlobalTables::GetIntConstTable().GetOrCreateIntConst(
C, *ArrTy->GetElemType()));
if (--Remaining == 0)
break;
}
// Add the terminator, if it fits
if (Remaining > 0) {
Agg->PushBack(createZero(ArrTy->GetElemType()));
}
return Agg;
} else {
return Builder->GetCurrentFuncCodeMp()->New<MIRStrConst>(SIdx, *Ty);
}
} else if (InitNode->op == OP_addrof) {
AddrofNode *AddrOf = static_cast<AddrofNode *>(InitNode);
return Builder->GetCurrentFuncCodeMp()->New<MIRAddrofConst>(
AddrOf->GetStIdx(), AddrOf->GetFieldID(), *Ty);
} else if (InitNode->op == OP_addroflabel) {
AddroflabelNode *AddrOf = static_cast<AddroflabelNode *>(InitNode);
return Builder->GetCurrentFuncCodeMp()->New<MIRLblConst>(
AddrOf->GetOffset(), Builder->GetCurrentFunction()->GetPuidx(), *Ty);
} else if (InitNode->op == OP_addroffunc) {
AddroffuncNode *AOF = static_cast<AddroffuncNode *>(InitNode);
return Builder->GetCurrentFuncCodeMp()->New<MIRAddroffuncConst>(
AOF->GetPUIdx(), *Ty);
} else if (InitNode->op == OP_iaddrof) {
IaddrofNode *IAddrOf = static_cast<IaddrofNode *>(InitNode);
BaseNode *Base = IAddrOf->Opnd(0);
// Find the offset of the field.
size_t FieldOffset = 0;
if (IAddrOf->GetFieldID()) {
auto UO =
llvm::dyn_cast<clang::UnaryOperator>(InitExpr->IgnoreParenCasts());
ASSERT(UO, "Expected unary operator");
auto ME = llvm::dyn_cast<clang::MemberExpr>(
UO->getSubExpr()->IgnoreParenCasts());
ASSERT(ME, "Expected member expression");
uint64_t OffsetBits = Context->getFieldOffset(ME->getMemberDecl());
FieldOffset += (OffsetBits / 8);
}
// Handle an address of an array element, e.g. &x[4]
if (Base->GetOpCode() == OP_array) {
ArrayNode *Array = static_cast<ArrayNode *>(Base);
BaseNode *ArrayBase = Array->GetBase();
if (ArrayBase->GetOpCode() == OP_addrof) {
AddrofNode *ArrayAddr = static_cast<AddrofNode *>(ArrayBase);
StIdx BaseStIdx = ArrayAddr->GetStIdx();
size_t ArrayOffset = 0;
bool Safe = computeArrayOffset(ArrayOffset, Array);
ASSERT(Safe, "Unable to compute array offset");
return Builder->GetCurrentFuncCodeMp()->New<MIRAddrofConst>(
BaseStIdx, ArrayAddr->GetFieldID(), *Ty, ArrayOffset + FieldOffset);
} else if (ArrayBase->GetOpCode() == OP_conststr) {
ConststrNode *ConstStr = static_cast<ConststrNode *>(ArrayBase);
ASSERT(Array->NumOpnds() == 2,
"Invalid array access on string constant");
BaseNode *IndexNode = Array->GetNopndAt(1);
int64_t Val;
bool Safe = evaluateNodeAsInt(Val, IndexNode);
ASSERT(Safe, "Unable to determine array offset");
const std::string &InitialString =
GlobalTables::GetUStrTable().GetStringFromStrIdx(
ConstStr->GetStrIdx());
return Builder->GetCurrentFuncCodeMp()->New<MIRStrConst>(
InitialString.substr(Val), *Ty);
}
} else if (Base->GetOpCode() == OP_constval) {
// This handles the case where the code is attempting to get the offset
// of a structure field by using the following type of expression:
// &((struct s *)0)->b)
if (auto UO = llvm::dyn_cast<clang::UnaryOperator>(
InitExpr->IgnoreParenCasts())) {
if (auto ME = llvm::dyn_cast<clang::MemberExpr>(
UO->getSubExpr()->IgnoreParenCasts())) {
ConstvalNode *ConstNode = static_cast<ConstvalNode *>(Base);
MIRConst *Const = ConstNode->GetConstVal();
ASSERT(Const->GetKind() == kConstInt,
"Only an integer is allowed here");
MIRIntConst *IntConst = static_cast<MIRIntConst *>(Const);
int64_t Base = IntConst->GetValue();
uint64_t OffsetBits = Context->getFieldOffset(ME->getMemberDecl());
return GlobalTables::GetIntConstTable().GetOrCreateIntConst(
Base + OffsetBits / 8, *Ty);
}
}
} else if (Base->GetOpCode() == OP_addrof) {
AddrofNode *AddrOf = static_cast<AddrofNode *>(Base);
return Builder->GetCurrentFuncCodeMp()->New<MIRAddrofConst>(
AddrOf->GetStIdx(), AddrOf->GetFieldID(), *Ty, FieldOffset);
} else if (Base->GetOpCode() == OP_add) {
BinaryNode *AddNode = static_cast<BinaryNode *>(Base);
BaseNode *LhsNode = AddNode->GetBOpnd(0);
BaseNode *RhsNode = AddNode->GetBOpnd(1);
if (LhsNode->GetOpCode() == OP_addrof &&
RhsNode->GetOpCode() == OP_constval) {
AddrofNode *AddrOf = static_cast<AddrofNode *>(LhsNode);
ConstvalNode *RhsConst = static_cast<ConstvalNode *>(RhsNode);
ASSERT(RhsConst->GetConstVal()->GetKind() == kConstInt,
"expected int const");
MIRIntConst *IntConst =
static_cast<MIRIntConst *>(RhsConst->GetConstVal());
int64_t Val = IntConst->GetValue();
return Builder->GetCurrentFuncCodeMp()->New<MIRAddrofConst>(
AddrOf->GetStIdx(), AddrOf->GetFieldID(), *Ty, Val + FieldOffset);
} else if (RhsNode->GetOpCode() == OP_addrof &&
LhsNode->GetOpCode() == OP_constval) {
AddrofNode *AddrOf = static_cast<AddrofNode *>(RhsNode);
ConstvalNode *LhsConst = static_cast<ConstvalNode *>(LhsNode);
ASSERT(LhsConst->GetConstVal()->GetKind() == kConstInt,
"expected int const");
MIRIntConst *IntConst =
static_cast<MIRIntConst *>(LhsConst->GetConstVal());
int64_t Val = IntConst->GetValue();
return Builder->GetCurrentFuncCodeMp()->New<MIRAddrofConst>(
AddrOf->GetStIdx(), AddrOf->GetFieldID(), *Ty, Val + FieldOffset);
}
}
} else if (InitNode->GetOpCode() == OP_array) {
ArrayNode *Array = static_cast<ArrayNode *>(InitNode);
BaseNode *ArrayBase = Array->GetBase();
if (ArrayBase->GetOpCode() == OP_addrof) {
AddrofNode *ArrayAddr = static_cast<AddrofNode *>(ArrayBase);
StIdx BaseStIdx = ArrayAddr->GetStIdx();
size_t ArrayOffset = 0;
bool Safe = computeArrayOffset(ArrayOffset, Array);
ASSERT(Safe, "Unable to compute array offset");
return Builder->GetCurrentFuncCodeMp()->New<MIRAddrofConst>(
BaseStIdx, ArrayAddr->GetFieldID(), *Ty, ArrayOffset);
} else if (ArrayBase->GetOpCode() == OP_conststr) {
ConststrNode *ConstStr = static_cast<ConststrNode *>(ArrayBase);
ASSERT(Array->NumOpnds() == 2, "Invalid array access on string constant");
BaseNode *IndexNode = Array->GetNopndAt(1);
int64_t Val;
bool Safe = evaluateNodeAsInt(Val, IndexNode);
ASSERT(Safe, "Unable to determine array offset");
const std::string &InitialString =
GlobalTables::GetUStrTable().GetStringFromStrIdx(
ConstStr->GetStrIdx());
return Builder->GetCurrentFuncCodeMp()->New<MIRStrConst>(
InitialString.substr(Val), *Ty);
}
} else if (InitNode->GetOpCode() == OP_add) {
BinaryNode *Bin = static_cast<BinaryNode *>(InitNode);
BaseNode *Lhs = Bin->GetBOpnd(0);
BaseNode *Rhs = Bin->GetBOpnd(1);
// Look for this type of expression: "foo" + 1
if (Lhs->GetOpCode() == OP_conststr && Rhs->GetOpCode() == OP_constval) {
ConststrNode *LhsConstStr = static_cast<ConststrNode *>(Lhs);
ConstvalNode *RhsConstNode = static_cast<ConstvalNode *>(Rhs);
MIRConst *RhsConst = RhsConstNode->GetConstVal();
ASSERT(RhsConst->GetKind() == kConstInt, "Expected int offset");
MIRIntConst *IntConst = static_cast<MIRIntConst *>(RhsConst);
std::string Str = GlobalTables::GetUStrTable().GetStringFromStrIdx(
LhsConstStr->GetStrIdx());
int64_t Offset = IntConst->GetValue();
ASSERT(Offset >= 0 && Offset < (int64_t)Str.length(),
"Invalid offset beyond length of string constant");
return Builder->GetCurrentFuncCodeMp()->New<MIRStrConst>(
Str.substr(Offset), *Ty);
}
}
if (MIRConst *ConstVal = evaluateExprAsConst(InitExpr, Ty)) {
return ConstVal;
}
LogInfo::MapleLogger()
<< "Error: Unable to evaluate initializer as a constant\n";
InitNode->Dump();
return nullptr;
}
MIRConst *Clang2MapleVisitor::completeArrayInitializer(MIRAggConst *Agg,
MIRArrayType *ArrTy) {
// First, complete any partially initialized inner arrays
for (size_t Elem = 0; Elem < Agg->GetConstVec().size(); Elem++) {
MIRConst *Const = Agg->GetConstVecItem(Elem);
if (Const->GetKind() == kConstAggConst) {
// An agg is also used for a struct, but we only care about arrays here
MIRType *ElemTy = ArrTy->GetElemType();
if (ElemTy->GetKind() == kTypeArray) {
completeArrayInitializer(static_cast<MIRAggConst *>(Const),
static_cast<MIRArrayType *>(ElemTy));
}
}
}
// Then complete this level of the array
MIRConst *Zero = createZero(ArrTy->GetElemType());
for (size_t Inited = Agg->GetConstVec().size(),
ArraySize = ArrTy->GetSizeArrayItem(0);
Inited < ArraySize; ++Inited) {
Agg->PushBack(Zero);
}
return Agg;
}
MIRType *Clang2MapleVisitor::isHomogenousAggregate(MIRType *Ty) {
MIRType *ElemTy = nullptr;
if (Ty->IsStructType()) {
MIRStructType *StructTy = static_cast<MIRStructType *>(Ty);
for (auto FieldPair : StructTy->GetFields()) {
MIRType *FieldTy =
GlobalTables::GetTypeTable().GetTypeFromTyIdx(FieldPair.second.first);
if (FieldTy->GetKind() == kTypeArray) {
MIRArrayType *ArrayTy = static_cast<MIRArrayType *>(FieldTy);
MIRType *ArrayElemTy = ArrayTy->GetElemType();
if (!PrimitiveType(ArrayElemTy->GetPrimType()).IsFloat()) {
return nullptr;
}
FieldTy = ArrayElemTy;
} else if (!PrimitiveType(FieldTy->GetPrimType()).IsFloat()) {
return nullptr;
}
if (!ElemTy) {
ElemTy = FieldTy;
} else if (ElemTy != FieldTy) {
return nullptr;
}
}
}
return ElemTy;
}
bool Clang2MapleVisitor::passInGeneralRegisters(MIRType *Ty) {
if (Ty->GetSize() > 16)
return false;
if (PrimitiveType(Ty->GetPrimType()).IsFloat())
return false;
if (isHomogenousAggregate(Ty))
return false;
return true;
}
bool Clang2MapleVisitor::passInFloatRegisters(MIRType *Ty) {
if (Ty->GetSize() > 16)
return false;
return PrimitiveType(Ty->GetPrimType()).IsFloat();
}
std::unique_ptr<clang::tooling::FrontendActionFactory>
clang2MapleFrontendActionFactory() {
class Clang2MapleFrontendActionFactory
: public clang::tooling::FrontendActionFactory {
public:
Clang2MapleFrontendActionFactory() {}
std::unique_ptr<clang::FrontendAction> create() override {
return std::make_unique<Clang2MapleAction>();
}
};
return std::unique_ptr<clang::tooling::FrontendActionFactory>(
new Clang2MapleFrontendActionFactory());
}
static MIRStorageClass StorageClass2Mpl(clang::StorageClass SC) {
switch (SC) {
case clang::SC_None:
return kScGlobal; // FIXME: Not sure what should return here
case clang::SC_Extern:
case clang::SC_PrivateExtern:
return kScExtern;
case clang::SC_Static:
return kScFstatic; // FIXME: Need to differentiate between pstatic and
// fstatic
case clang::SC_Auto:
return kScAuto;
case clang::SC_Register:
return kScInvalid; // FIXME: Find the correct alternative for this
}
return kScInvalid;
}
static Opcode BinOpcode2Mpl(clang::BinaryOperatorKind Op, bool isSigned) {
switch (Op) {
case clang::BO_Mul:
case clang::BO_MulAssign:
return OP_mul;
case clang::BO_Div:
case clang::BO_DivAssign:
return OP_div;
case clang::BO_Rem:
case clang::BO_RemAssign:
return OP_rem;
case clang::BO_Add:
case clang::BO_AddAssign:
return OP_add;
case clang::BO_Sub:
case clang::BO_SubAssign:
return OP_sub;
case clang::BO_Shl:
case clang::BO_ShlAssign:
return OP_shl;
case clang::BO_Shr:
case clang::BO_ShrAssign:
if (isSigned)
return OP_ashr;
else
return OP_lshr;
case clang::BO_Cmp:
return OP_cmp;
case clang::BO_LT:
return OP_lt;
case clang::BO_GT:
return OP_gt;
case clang::BO_LE:
return OP_le;
case clang::BO_GE:
return OP_ge;
case clang::BO_EQ:
return OP_eq;
case clang::BO_NE:
return OP_ne;
case clang::BO_And:
case clang::BO_AndAssign:
return OP_band;
case clang::BO_Xor:
case clang::BO_XorAssign:
return OP_bxor;
case clang::BO_Or:
case clang::BO_OrAssign:
return OP_bior;
case clang::BO_LAnd:
return OP_land;
case clang::BO_LOr:
return OP_lior;
default:
return OP_undef;
}
}
static bool isAssign(Opcode Op) {
return Op == OP_dassign || Op == OP_iassign || kOpcodeInfo.IsCallAssigned(Op);
}
static bool isPointerType(MIRType *Ty) {
return Ty->IsMIRPtrType() || Ty->GetKind() == kTypeArray;
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。