-betterC: Use C assert function

Instead of druntime's _d_assert[_msg], _d_arraybounds and
_d_switch_error.

Tested by dmd-testsuite's runnable/cassert and compilable/betterCarray.
This commit is contained in:
Martin 2017-10-13 19:49:24 +02:00
parent fbbbeecaca
commit 30b858781b
10 changed files with 106 additions and 32 deletions

View file

@ -12,6 +12,7 @@
#include "declaration.h"
#include "module.h"
#include "mtype.h"
#include "gen/arrays.h"
#include "gen/dvalue.h"
#include "gen/irstate.h"
#include "gen/llvm.h"
@ -91,14 +92,7 @@ DLValue *DtoAAIndex(Loc &loc, Type *type, DValue *aa, DValue *key,
gIR->scope() = IRScope(failbb);
llvm::Function *errorfn =
getRuntimeFunction(loc, gIR->module, "_d_arraybounds");
gIR->CreateCallOrInvoke(
errorfn, DtoModuleFileName(gIR->func()->decl->getModule(), loc),
DtoConstUint(loc.linnum));
// the function does not return
gIR->ir->CreateUnreachable();
DtoBoundsCheckFailCall(gIR, loc);
// if ok, proceed in okbb
gIR->scope() = IRScope(okbb);

View file

@ -1377,12 +1377,17 @@ void DtoIndexBoundsCheck(Loc &loc, DValue *arr, DValue *index) {
}
void DtoBoundsCheckFailCall(IRState *irs, Loc &loc) {
llvm::Function *errorfn =
getRuntimeFunction(loc, irs->module, "_d_arraybounds");
irs->CreateCallOrInvoke(
errorfn, DtoModuleFileName(irs->func()->decl->getModule(), loc),
DtoConstUint(loc.linnum));
Module *const module = irs->func()->decl->getModule();
// the function does not return
irs->ir->CreateUnreachable();
if (global.params.betterC) {
DtoCAssert(module, loc, DtoConstCString("array overflow"));
} else {
llvm::Function *errorfn =
getRuntimeFunction(loc, irs->module, "_d_arraybounds");
irs->CreateCallOrInvoke(errorfn, DtoModuleFileName(module, loc),
DtoConstUint(loc.linnum));
// the function does not return
irs->ir->CreateUnreachable();
}
}

View file

@ -278,11 +278,37 @@ void DtoAssert(Module *M, Loc &loc, DValue *msg) {
gIR->ir->CreateUnreachable();
}
void DtoCAssert(Module *M, Loc &loc, LLValue *msg) {
const auto file = DtoConstCString(loc.filename ? loc.filename
: M->srcfile->name->toChars());
const auto line = DtoConstUint(loc.linnum);
const auto fn = getCAssertFunction(loc, gIR->module);
llvm::SmallVector<LLValue *, 4> args;
if (global.params.targetTriple->isOSDarwin()) {
const auto irFunc = gIR->func();
const auto funcName =
irFunc && irFunc->decl ? irFunc->decl->toPrettyChars() : "";
args.push_back(DtoConstCString(funcName));
args.push_back(file);
args.push_back(line);
args.push_back(msg);
} else {
args.push_back(msg);
args.push_back(file);
args.push_back(line);
}
gIR->funcGen().callOrInvoke(fn, args);
gIR->ir->CreateUnreachable();
}
/******************************************************************************
* MODULE FILE NAME
******************************************************************************/
LLValue *DtoModuleFileName(Module *M, const Loc &loc) {
LLConstant *DtoModuleFileName(Module *M, const Loc &loc) {
return DtoConstString(loc.filename ? loc.filename
: M->srcfile->name->toChars());
}

View file

@ -61,9 +61,10 @@ LLValue *DtoAllocaDump(LLValue *val, LLType *asType, int alignment = 0,
// assertion generator
void DtoAssert(Module *M, Loc &loc, DValue *msg);
void DtoCAssert(Module *M, Loc &loc, LLValue *msg);
// returns module file name
LLValue *DtoModuleFileName(Module *M, const Loc &loc);
LLConstant *DtoModuleFileName(Module *M, const Loc &loc);
/// emits goto to LabelStatement with the target identifier
void DtoGoto(Loc &loc, LabelDsymbol *target);

View file

@ -160,6 +160,21 @@ llvm::Function *getRuntimeFunction(const Loc &loc, llvm::Module &target,
////////////////////////////////////////////////////////////////////////////////
static const char *getCAssertFunctionName() {
if (global.params.targetTriple->isOSDarwin()) {
return "__assert_rtn";
} else if (global.params.targetTriple->isWindowsMSVCEnvironment()) {
return "_assert";
}
return "__assert";
}
llvm::Function *getCAssertFunction(const Loc &loc, llvm::Module &target) {
return getRuntimeFunction(loc, target, getCAssertFunctionName());
}
////////////////////////////////////////////////////////////////////////////////
// extern (D) alias dg_t = int delegate(void*);
static Type *rt_dg1() {
static Type *dg_t = nullptr;
@ -330,6 +345,17 @@ static void buildRuntimeModule() {
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// C assert function:
// OSX: void __assert_rtn(const char *func, const char *file, unsigned line,
// const char *msg)
// else: void [_]_assert(const char *msg, const char *file, unsigned line)
createFwdDecl(
LINKc, Type::tvoid, {getCAssertFunctionName()},
global.params.targetTriple->isOSDarwin()
? llvm::ArrayRef<Type *>({voidPtrTy, voidPtrTy, uintTy, voidPtrTy})
: llvm::ArrayRef<Type *>({voidPtrTy, voidPtrTy, uintTy}),
{}, Attr_Cold_NoReturn);
// void _d_assert(string file, uint line)
// void _d_arraybounds(string file, uint line)
createFwdDecl(LINKc, Type::tvoid, {"_d_assert", "_d_arraybounds"},

View file

@ -30,6 +30,8 @@ void freeRuntime();
llvm::Function *getRuntimeFunction(const Loc &loc, llvm::Module &target,
const char *name);
llvm::Function *getCAssertFunction(const Loc &loc, llvm::Module &target);
void emitInstrumentationFnEnter(FuncDeclaration *decl);
void emitInstrumentationFnLeave(FuncDeclaration *decl);

View file

@ -1644,15 +1644,21 @@ public:
stmt->loc.toChars());
LOG_SCOPE;
assert(!irs->dcomputetarget);
auto &PGO = irs->funcGen().pgo;
PGO.setCurrentStmt(stmt);
Module *const module = irs->func()->decl->getModule();
if (global.params.betterC) {
DtoCAssert(module, stmt->loc, DtoConstCString("no switch default"));
return;
}
llvm::Function *fn =
getRuntimeFunction(stmt->loc, irs->module, "_d_switch_error");
LLValue *moduleInfoSymbol =
getIrModule(irs->func()->decl->getModule())->moduleInfoSymbol();
LLValue *moduleInfoSymbol = getIrModule(module)->moduleInfoSymbol();
LLType *moduleInfoType = DtoType(Module::moduleinfo->type);
LLCallSite call = irs->CreateCallOrInvoke(

View file

@ -1684,8 +1684,16 @@ public:
* msg is not evaluated at all. So should use toElemDtor()
* instead of toElem().
*/
DtoAssert(p->func()->decl->getModule(), e->loc,
e->msg ? toElemDtor(e->msg) : nullptr);
DValue *const msg = e->msg ? toElemDtor(e->msg) : nullptr;
Module *const module = p->func()->decl->getModule();
if (global.params.betterC) {
const auto cMsg =
msg ? DtoArrayPtr(msg) // assuming `msg` is null-terminated, like DMD
: DtoConstCString(e->e1->toChars());
DtoCAssert(module, e->e1->loc, cMsg);
} else {
DtoAssert(module, e->loc, msg);
}
// passed:
p->scope() = IRScope(passedbb);

View file

@ -413,12 +413,13 @@ LLConstant *DtoConstFP(Type *t, const real_t value) {
////////////////////////////////////////////////////////////////////////////////
LLConstant *DtoConstString(const char *str) {
LLConstant *DtoConstCString(const char *str) {
llvm::StringRef s(str ? str : "");
llvm::GlobalVariable *gvar = (gIR->stringLiteral1ByteCache.find(s) ==
gIR->stringLiteral1ByteCache.end())
? nullptr
: gIR->stringLiteral1ByteCache[s];
const auto it = gIR->stringLiteral1ByteCache.find(s);
llvm::GlobalVariable *gvar =
it == gIR->stringLiteral1ByteCache.end() ? nullptr : it->getValue();
if (gvar == nullptr) {
llvm::Constant *init =
llvm::ConstantDataArray::getString(gIR->context(), s, true);
@ -432,12 +433,16 @@ LLConstant *DtoConstString(const char *str) {
#endif
gIR->stringLiteral1ByteCache[s] = gvar;
}
LLConstant *idxs[] = {DtoConstUint(0), DtoConstUint(0)};
return DtoConstSlice(DtoConstSize_t(s.size()),
llvm::ConstantExpr::getGetElementPtr(
gvar->getInitializer()->getType(),
gvar, idxs, true),
Type::tchar->arrayOf());
return llvm::ConstantExpr::getGetElementPtr(gvar->getInitializer()->getType(),
gvar, idxs, true);
}
LLConstant *DtoConstString(const char *str) {
LLConstant *cString = DtoConstCString(str);
LLConstant *length = DtoConstSize_t(str ? strlen(str) : 0);
return DtoConstSlice(length, cString, Type::tchar->arrayOf());
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -97,6 +97,7 @@ LLConstantInt *DtoConstInt(int i);
LLConstantInt *DtoConstUbyte(unsigned char i);
LLConstant *DtoConstFP(Type *t, real_t value);
LLConstant *DtoConstCString(const char *);
LLConstant *DtoConstString(const char *);
LLConstant *DtoConstBool(bool);