aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/ArrayHandler.cc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CodeGen/ArrayHandler.cc')
-rw-r--r--lib/CodeGen/ArrayHandler.cc152
1 files changed, 140 insertions, 12 deletions
diff --git a/lib/CodeGen/ArrayHandler.cc b/lib/CodeGen/ArrayHandler.cc
index d21d91c..c647d58 100644
--- a/lib/CodeGen/ArrayHandler.cc
+++ b/lib/CodeGen/ArrayHandler.cc
@@ -91,8 +91,6 @@ void ArrayHandler::emitArrayDeclare(ArrayDeclareStmtAST *Stmt, CodeGen &CG) {
std::vector<Value*> Lows;
std::vector<Value*> Highs;
- std::vector<Value*> Dims;
- Value *TotalElements = ConstantInt::get(*TheContext, APInt(64, 1));
for (const auto &Pair : Stmt->getBounds()) {
Value *L = CG.emitExpr(Pair.first.get());
@@ -104,18 +102,11 @@ void ArrayHandler::emitArrayDeclare(ArrayDeclareStmtAST *Stmt, CodeGen &CG) {
Lows.push_back(L);
Highs.push_back(R);
-
- Value *Diff = Builder->CreateSub(R, L, Name + "_dim_diff");
- Value *DimSize = Builder->CreateAdd(Diff, ConstantInt::get(*TheContext, APInt(64, 1)), Name + "_dim_size");
- Dims.push_back(DimSize);
- TotalElements = Builder->CreateMul(TotalElements, DimSize, Name + "_total_elems");
}
- std::vector<Value*> Multipliers(Rank);
- Multipliers[Rank - 1] = ConstantInt::get(*TheContext, APInt(64, 1));
- for (int i = Rank - 2; i >= 0; --i) {
- Multipliers[i] = Builder->CreateMul(Multipliers[i + 1], Dims[i + 1], Name + "_mult");
- }
+ std::vector<Value*> Multipliers;
+ Value *TotalElements = nullptr;
+ computeDimsAndMultipliers(Name, Lows, Highs, Multipliers, TotalElements);
ArrayMetadata Meta;
Meta.Rank = Rank;
@@ -144,6 +135,30 @@ void ArrayHandler::emitArrayDeclare(ArrayDeclareStmtAST *Stmt, CodeGen &CG) {
CG.registerSymbol(Name, Alloca, ElemInfo->Name, true);
}
+void ArrayHandler::computeDimsAndMultipliers(const std::string &Name,
+ const std::vector<Value*> &Lows,
+ const std::vector<Value*> &Highs,
+ std::vector<Value*> &Multipliers,
+ Value *&TotalElements) {
+ int Rank = static_cast<int>(Lows.size());
+ std::vector<Value*> Dims;
+ TotalElements = ConstantInt::get(*TheContext, APInt(64, 1));
+
+ for (int I = 0; I < Rank; ++I) {
+ Value *Diff = Builder->CreateSub(Highs[I], Lows[I], Name + "_dim_diff");
+ Value *DimSize = Builder->CreateAdd(Diff, ConstantInt::get(*TheContext, APInt(64, 1)),
+ Name + "_dim_size");
+ Dims.push_back(DimSize);
+ TotalElements = Builder->CreateMul(TotalElements, DimSize, Name + "_total_elems");
+ }
+
+ Multipliers.assign(Rank, nullptr);
+ Multipliers[Rank - 1] = ConstantInt::get(*TheContext, APInt(64, 1));
+ for (int I = Rank - 2; I >= 0; --I) {
+ Multipliers[I] = Builder->CreateMul(Multipliers[I + 1], Dims[I + 1], Name + "_mult");
+ }
+}
+
bool ArrayHandler::emitCheckedIndices(const std::string &Name,
const std::vector<std::unique_ptr<ExprAST>> &IndexExprs,
int Line,
@@ -238,6 +253,119 @@ std::map<std::string, ArrayMetadata> ArrayHandler::exchangeTable(std::map<std::s
return NewTable;
}
+void ArrayHandler::bindArrayParameter(const std::string &Name,
+ const std::string &ElemTypeName,
+ Value *DataPtr,
+ const std::vector<Value*> &LBs,
+ const std::vector<Value*> &UBs,
+ bool MakeCopy,
+ CodeGen &CG) {
+ const TypeInfo *ElemInfo = Types.resolve(ElemTypeName);
+ if (!ElemInfo || !ElemInfo->LLVMType || ElemInfo->isVoid()) {
+ CG.reportError("Unknown array element type %s", ElemTypeName.c_str());
+ return;
+ }
+
+ std::vector<Value*> Multipliers;
+ Value *TotalElements = nullptr;
+ computeDimsAndMultipliers(Name, LBs, UBs, Multipliers, TotalElements);
+
+ ArrayMetadata Meta;
+ Meta.Rank = static_cast<int>(LBs.size());
+ Meta.ElementTypeName = ElemInfo->Name;
+ Meta.ElementType = ElemInfo->LLVMType;
+ Meta.ElementSizeC = Types.getSizeOfConstant(ElemInfo->LLVMType);
+ Meta.LowerBounds = LBs;
+ Meta.UpperBounds = UBs;
+ Meta.Multipliers = std::move(Multipliers);
+ ArrayTable[Name] = Meta;
+
+ Value *Ptr = DataPtr;
+ if (MakeCopy) {
+ // BYVAL: whole-buffer copy so callee writes stay invisible to the
+ // caller. The copy is malloc'd and never freed, consistent with the
+ // project-wide string policy.
+ Value *TotalBytes = Builder->CreateMul(TotalElements, Meta.ElementSizeC,
+ Name + "_copy_bytes");
+ Value *Copy = Builder->CreateCall(MallocFunc, TotalBytes, Name + "_copy");
+ FunctionType *MemcpyType = FunctionType::get(
+ PointerType::getUnqual(*TheContext),
+ {PointerType::getUnqual(*TheContext), PointerType::getUnqual(*TheContext),
+ Type::getInt64Ty(*TheContext)},
+ false);
+ FunctionCallee MemcpyFunc = TheModule->getOrInsertFunction("memcpy", MemcpyType);
+ Builder->CreateCall(MemcpyFunc, {Copy, DataPtr, TotalBytes});
+ Ptr = Copy;
+ }
+
+ Function *TheFunction = Builder->GetInsertBlock()->getParent();
+ AllocaInst *Alloca = CG.CreateEntryBlockAlloca(TheFunction, PointerType::getUnqual(*TheContext), Name);
+ Builder->CreateStore(Ptr, Alloca);
+
+ CG.registerSymbol(Name, Alloca, ElemInfo->Name, true);
+}
+
+bool ArrayHandler::emitArrayArgument(ExprAST *ArgExpr,
+ const std::string &ElemTypeName,
+ int Rank,
+ const std::vector<std::pair<int64_t, int64_t>> &DeclaredBounds,
+ const std::string &Callee,
+ int Line,
+ CodeGen &CG,
+ std::vector<Value*> &Out) {
+ auto *Var = dynamic_cast<VariableExprAST*>(ArgExpr);
+ const ArrayMetadata *Meta = Var ? getMetadata(Var->getName()) : nullptr;
+ if (!Meta) {
+ CG.reportError("Argument to %s must be a whole array variable (ARRAY OF %s)",
+ Callee.c_str(), ElemTypeName.c_str());
+ return false;
+ }
+ if (Meta->ElementTypeName != ElemTypeName) {
+ CG.reportError("Array argument %s to %s must have element type %s (got %s)",
+ Var->getName().c_str(), Callee.c_str(),
+ ElemTypeName.c_str(), Meta->ElementTypeName.c_str());
+ return false;
+ }
+ if (Meta->Rank != Rank) {
+ CG.reportError("Array argument %s to %s must have %d dimension%s (got %d)",
+ Var->getName().c_str(), Callee.c_str(),
+ Rank, Rank == 1 ? "" : "s", Meta->Rank);
+ return false;
+ }
+
+ // Bounded parameters are a contract: verified at compile time when the
+ // caller's bounds are constants (the common case), at run time otherwise.
+ for (size_t D = 0; D < DeclaredBounds.size(); ++D) {
+ int64_t DeclLo = DeclaredBounds[D].first;
+ int64_t DeclHi = DeclaredBounds[D].second;
+ auto *ActLo = dyn_cast<ConstantInt>(Meta->LowerBounds[D]);
+ auto *ActHi = dyn_cast<ConstantInt>(Meta->UpperBounds[D]);
+ if (ActLo && ActHi) {
+ if (ActLo->getSExtValue() != DeclLo || ActHi->getSExtValue() != DeclHi) {
+ CG.reportError("Array argument %s to %s has bounds [%lld:%lld] but the parameter declares [%lld:%lld]",
+ Var->getName().c_str(), Callee.c_str(),
+ static_cast<long long>(ActLo->getSExtValue()),
+ static_cast<long long>(ActHi->getSExtValue()),
+ static_cast<long long>(DeclLo),
+ static_cast<long long>(DeclHi));
+ return false;
+ }
+ } else {
+ RuntimeChecker.emitArrayArgBoundsCheck(Meta->LowerBounds[D], Meta->UpperBounds[D],
+ DeclLo, DeclHi, Line);
+ }
+ }
+
+ Value *DataPtr = getArrayBasePointer(Var->getName());
+ if (!DataPtr) return false;
+ Out.push_back(DataPtr);
+ for (int D = 0; D < Rank; ++D) {
+ Out.push_back(Meta->LowerBounds[D]);
+ Out.push_back(Meta->UpperBounds[D]);
+ }
+ return true;
+}
+
bool ArrayHandler::tryEmitArrayOutput(ExprAST *Expr, CodeGen &CG) {
std::string Name;
const std::vector<std::unique_ptr<ExprAST>> *IndexExprs = nullptr;