mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-01 07:30:43 +03:00
-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:
parent
fbbbeecaca
commit
30b858781b
10 changed files with 106 additions and 32 deletions
10
gen/aa.cpp
10
gen/aa.cpp
|
@ -12,6 +12,7 @@
|
||||||
#include "declaration.h"
|
#include "declaration.h"
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
#include "mtype.h"
|
#include "mtype.h"
|
||||||
|
#include "gen/arrays.h"
|
||||||
#include "gen/dvalue.h"
|
#include "gen/dvalue.h"
|
||||||
#include "gen/irstate.h"
|
#include "gen/irstate.h"
|
||||||
#include "gen/llvm.h"
|
#include "gen/llvm.h"
|
||||||
|
@ -91,14 +92,7 @@ DLValue *DtoAAIndex(Loc &loc, Type *type, DValue *aa, DValue *key,
|
||||||
|
|
||||||
gIR->scope() = IRScope(failbb);
|
gIR->scope() = IRScope(failbb);
|
||||||
|
|
||||||
llvm::Function *errorfn =
|
DtoBoundsCheckFailCall(gIR, loc);
|
||||||
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();
|
|
||||||
|
|
||||||
// if ok, proceed in okbb
|
// if ok, proceed in okbb
|
||||||
gIR->scope() = IRScope(okbb);
|
gIR->scope() = IRScope(okbb);
|
||||||
|
|
|
@ -1377,12 +1377,17 @@ void DtoIndexBoundsCheck(Loc &loc, DValue *arr, DValue *index) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DtoBoundsCheckFailCall(IRState *irs, Loc &loc) {
|
void DtoBoundsCheckFailCall(IRState *irs, Loc &loc) {
|
||||||
llvm::Function *errorfn =
|
Module *const module = irs->func()->decl->getModule();
|
||||||
getRuntimeFunction(loc, irs->module, "_d_arraybounds");
|
|
||||||
irs->CreateCallOrInvoke(
|
|
||||||
errorfn, DtoModuleFileName(irs->func()->decl->getModule(), loc),
|
|
||||||
DtoConstUint(loc.linnum));
|
|
||||||
|
|
||||||
// the function does not return
|
if (global.params.betterC) {
|
||||||
irs->ir->CreateUnreachable();
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -278,11 +278,37 @@ void DtoAssert(Module *M, Loc &loc, DValue *msg) {
|
||||||
gIR->ir->CreateUnreachable();
|
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
|
* MODULE FILE NAME
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
LLValue *DtoModuleFileName(Module *M, const Loc &loc) {
|
LLConstant *DtoModuleFileName(Module *M, const Loc &loc) {
|
||||||
return DtoConstString(loc.filename ? loc.filename
|
return DtoConstString(loc.filename ? loc.filename
|
||||||
: M->srcfile->name->toChars());
|
: M->srcfile->name->toChars());
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,9 +61,10 @@ LLValue *DtoAllocaDump(LLValue *val, LLType *asType, int alignment = 0,
|
||||||
|
|
||||||
// assertion generator
|
// assertion generator
|
||||||
void DtoAssert(Module *M, Loc &loc, DValue *msg);
|
void DtoAssert(Module *M, Loc &loc, DValue *msg);
|
||||||
|
void DtoCAssert(Module *M, Loc &loc, LLValue *msg);
|
||||||
|
|
||||||
// returns module file name
|
// 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
|
/// emits goto to LabelStatement with the target identifier
|
||||||
void DtoGoto(Loc &loc, LabelDsymbol *target);
|
void DtoGoto(Loc &loc, LabelDsymbol *target);
|
||||||
|
|
|
@ -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*);
|
// extern (D) alias dg_t = int delegate(void*);
|
||||||
static Type *rt_dg1() {
|
static Type *rt_dg1() {
|
||||||
static Type *dg_t = nullptr;
|
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_assert(string file, uint line)
|
||||||
// void _d_arraybounds(string file, uint line)
|
// void _d_arraybounds(string file, uint line)
|
||||||
createFwdDecl(LINKc, Type::tvoid, {"_d_assert", "_d_arraybounds"},
|
createFwdDecl(LINKc, Type::tvoid, {"_d_assert", "_d_arraybounds"},
|
||||||
|
|
|
@ -30,6 +30,8 @@ void freeRuntime();
|
||||||
llvm::Function *getRuntimeFunction(const Loc &loc, llvm::Module &target,
|
llvm::Function *getRuntimeFunction(const Loc &loc, llvm::Module &target,
|
||||||
const char *name);
|
const char *name);
|
||||||
|
|
||||||
|
llvm::Function *getCAssertFunction(const Loc &loc, llvm::Module &target);
|
||||||
|
|
||||||
void emitInstrumentationFnEnter(FuncDeclaration *decl);
|
void emitInstrumentationFnEnter(FuncDeclaration *decl);
|
||||||
void emitInstrumentationFnLeave(FuncDeclaration *decl);
|
void emitInstrumentationFnLeave(FuncDeclaration *decl);
|
||||||
|
|
||||||
|
|
|
@ -1644,15 +1644,21 @@ public:
|
||||||
stmt->loc.toChars());
|
stmt->loc.toChars());
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
assert(!irs->dcomputetarget);
|
assert(!irs->dcomputetarget);
|
||||||
|
|
||||||
auto &PGO = irs->funcGen().pgo;
|
auto &PGO = irs->funcGen().pgo;
|
||||||
PGO.setCurrentStmt(stmt);
|
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 =
|
llvm::Function *fn =
|
||||||
getRuntimeFunction(stmt->loc, irs->module, "_d_switch_error");
|
getRuntimeFunction(stmt->loc, irs->module, "_d_switch_error");
|
||||||
|
|
||||||
LLValue *moduleInfoSymbol =
|
LLValue *moduleInfoSymbol = getIrModule(module)->moduleInfoSymbol();
|
||||||
getIrModule(irs->func()->decl->getModule())->moduleInfoSymbol();
|
|
||||||
LLType *moduleInfoType = DtoType(Module::moduleinfo->type);
|
LLType *moduleInfoType = DtoType(Module::moduleinfo->type);
|
||||||
|
|
||||||
LLCallSite call = irs->CreateCallOrInvoke(
|
LLCallSite call = irs->CreateCallOrInvoke(
|
||||||
|
|
12
gen/toir.cpp
12
gen/toir.cpp
|
@ -1684,8 +1684,16 @@ public:
|
||||||
* msg is not evaluated at all. So should use toElemDtor()
|
* msg is not evaluated at all. So should use toElemDtor()
|
||||||
* instead of toElem().
|
* instead of toElem().
|
||||||
*/
|
*/
|
||||||
DtoAssert(p->func()->decl->getModule(), e->loc,
|
DValue *const msg = e->msg ? toElemDtor(e->msg) : nullptr;
|
||||||
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:
|
// passed:
|
||||||
p->scope() = IRScope(passedbb);
|
p->scope() = IRScope(passedbb);
|
||||||
|
|
|
@ -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::StringRef s(str ? str : "");
|
||||||
llvm::GlobalVariable *gvar = (gIR->stringLiteral1ByteCache.find(s) ==
|
|
||||||
gIR->stringLiteral1ByteCache.end())
|
const auto it = gIR->stringLiteral1ByteCache.find(s);
|
||||||
? nullptr
|
llvm::GlobalVariable *gvar =
|
||||||
: gIR->stringLiteral1ByteCache[s];
|
it == gIR->stringLiteral1ByteCache.end() ? nullptr : it->getValue();
|
||||||
|
|
||||||
if (gvar == nullptr) {
|
if (gvar == nullptr) {
|
||||||
llvm::Constant *init =
|
llvm::Constant *init =
|
||||||
llvm::ConstantDataArray::getString(gIR->context(), s, true);
|
llvm::ConstantDataArray::getString(gIR->context(), s, true);
|
||||||
|
@ -432,12 +433,16 @@ LLConstant *DtoConstString(const char *str) {
|
||||||
#endif
|
#endif
|
||||||
gIR->stringLiteral1ByteCache[s] = gvar;
|
gIR->stringLiteral1ByteCache[s] = gvar;
|
||||||
}
|
}
|
||||||
|
|
||||||
LLConstant *idxs[] = {DtoConstUint(0), DtoConstUint(0)};
|
LLConstant *idxs[] = {DtoConstUint(0), DtoConstUint(0)};
|
||||||
return DtoConstSlice(DtoConstSize_t(s.size()),
|
return llvm::ConstantExpr::getGetElementPtr(gvar->getInitializer()->getType(),
|
||||||
llvm::ConstantExpr::getGetElementPtr(
|
gvar, idxs, true);
|
||||||
gvar->getInitializer()->getType(),
|
}
|
||||||
gvar, idxs, true),
|
|
||||||
Type::tchar->arrayOf());
|
LLConstant *DtoConstString(const char *str) {
|
||||||
|
LLConstant *cString = DtoConstCString(str);
|
||||||
|
LLConstant *length = DtoConstSize_t(str ? strlen(str) : 0);
|
||||||
|
return DtoConstSlice(length, cString, Type::tchar->arrayOf());
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -97,6 +97,7 @@ LLConstantInt *DtoConstInt(int i);
|
||||||
LLConstantInt *DtoConstUbyte(unsigned char i);
|
LLConstantInt *DtoConstUbyte(unsigned char i);
|
||||||
LLConstant *DtoConstFP(Type *t, real_t value);
|
LLConstant *DtoConstFP(Type *t, real_t value);
|
||||||
|
|
||||||
|
LLConstant *DtoConstCString(const char *);
|
||||||
LLConstant *DtoConstString(const char *);
|
LLConstant *DtoConstString(const char *);
|
||||||
LLConstant *DtoConstBool(bool);
|
LLConstant *DtoConstBool(bool);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue