Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dmd2/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ struct Param
bool addMain; // LDC_FIXME: Implement.
bool allInst; // LDC_FIXME: Implement.
unsigned nestedTmpl; // maximum nested template instantiations
bool betterC; // be a "better C" compiler; no dependency on D runtime
#else
bool pic; // generate position-independent-code for shared libs
bool color; // use ANSI colors in console output
Expand All @@ -136,7 +137,6 @@ struct Param
bool nofloat; // code should not pull in floating point support
bool ignoreUnsupportedPragmas; // rather than error on them
bool enforcePropertySyntax;
bool betterC; // be a "better C" compiler; no dependency on D runtime
bool addMain; // add a default main() function
bool allInst; // generate code for all template instantiations
#endif
Expand Down
5 changes: 5 additions & 0 deletions driver/cl_options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,11 @@ cl::opt<bool, true>
cl::desc("implement http://wiki.dlang.org/DIP25 (experimental)"),
cl::location(global.params.useDIP25));

cl::opt<bool, true> betterC(
"betterC",
cl::desc("omit generating some runtime information and helper functions"),
cl::location(global.params.betterC));

cl::opt<unsigned char, true, CoverageParser> coverageAnalysis(
"cov", cl::desc("Compile-in code coverage analysis\n(use -cov=n for n% "
"minimum required coverage)"),
Expand Down
1 change: 1 addition & 0 deletions driver/ldmd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ Usage:\n\
files.d D source files\n\
@cmdfile read arguments from cmdfile\n\
-allinst generate code for all template instantiations\n\
-betterC omit generating some runtime information and helper functions\n\
-c do not link\n\
-color[=on|off] force colored console output on or off\n\
-conf=path use config file at path\n\
Expand Down
14 changes: 8 additions & 6 deletions driver/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -459,12 +459,10 @@ static void parseCommandLine(int argc, char **argv, Strings &sourceFiles,
}

if (noDefaultLib) {
deprecation(
Loc(),
"-nodefaultlib is deprecated, as "
"-defaultlib/-debuglib now override the existing list instead of "
"appending to it. Please use the latter instead.");
} else {
deprecation(Loc(), "-nodefaultlib is deprecated, as -defaultlib/-debuglib "
"now override the existing list instead of appending to "
"it. Please use the latter instead.");
} else if (!global.params.betterC) {
// Parse comma-separated default library list.
std::stringstream libNames(linkDebugLib ? debugLib : defaultLib);
while (libNames.good()) {
Expand Down Expand Up @@ -860,6 +858,10 @@ static void registerPredefinedVersions() {
VersionCondition::addPredefinedGlobalIdent("D_NoBoundsChecks");
}

if (global.params.betterC) {
VersionCondition::addPredefinedGlobalIdent("D_BetterC");
}

registerPredefinedTargetVersions();

// Pass sanitizer arguments to linker. Requires clang.
Expand Down
10 changes: 2 additions & 8 deletions gen/aa.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -91,14 +92,7 @@ DValue *DtoAAIndex(Loc &loc, Type *type, DValue *aa, DValue *key, bool lvalue) {

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);
Expand Down
21 changes: 13 additions & 8 deletions gen/arrays.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1216,12 +1216,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));

// the function does not return
irs->ir->CreateUnreachable();
Module *const module = irs->func()->decl->getModule();

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();
}
}
41 changes: 40 additions & 1 deletion gen/llvmhelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,11 +265,50 @@ 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 if (global.params.targetTriple.isOSSolaris()) {
const auto irFunc = gIR->func();
const auto funcName =
(irFunc && irFunc->decl) ? irFunc->decl->toPrettyChars() : "";
args.push_back(msg);
args.push_back(file);
args.push_back(line);
args.push_back(DtoConstCString(funcName));
} else if (global.params.targetTriple.getEnvironment() ==
llvm::Triple::Android) {
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->func()->scopes->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());
}
Expand Down
3 changes: 2 additions & 1 deletion gen/llvmhelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,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);
Expand Down
4 changes: 2 additions & 2 deletions gen/module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -743,8 +743,8 @@ void codegenModule(IRState *irs, Module *m, bool emitFullModuleInfo) {
}

// Skip emission of all the additional module metadata if requested by the
// user.
if (!m->noModuleInfo) {
// user or the betterC switch is on.
if (!global.params.betterC && !m->noModuleInfo) {
// generate ModuleInfo
genModuleInfo(m, emitFullModuleInfo);

Expand Down
42 changes: 42 additions & 0 deletions gen/runtime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,43 @@ llvm::GlobalVariable *getRuntimeGlobal(Loc &loc, llvm::Module &target,
g->getLinkage(), nullptr, g->getName());
}

// C assert function:
// OSX: void __assert_rtn(const char *func, const char *file, unsigned line,
// const char *msg)
// Android: void __assert(const char *file, int line, const char *msg)
// MSVC: void _assert(const char *msg, const char *file, unsigned line)
// Solaris: void __assert_c99(const char *assertion, const char *filename, int line_num,
// const char *funcname);
// else: void __assert(const char *msg, const char *file, unsigned line)

static const char *getCAssertFunctionName() {
if (global.params.targetTriple.isOSDarwin()) {
return "__assert_rtn";
} else if (global.params.targetTriple.isWindowsMSVCEnvironment()) {
return "_assert";
} else if (global.params.targetTriple.isOSSolaris()) {
return "__assert_c99";
}
return "__assert";
}

static std::vector<Type *> getCAssertFunctionParamTypes() {
const auto voidPtr = Type::tvoidptr;
const auto uint = Type::tuns32;

if (global.params.targetTriple.isOSDarwin() || global.params.targetTriple.isOSSolaris()) {
return {voidPtr, voidPtr, uint, voidPtr};
}
if (global.params.targetTriple.getEnvironment() == llvm::Triple::Android) {
return {voidPtr, uint, voidPtr};
}
return {voidPtr, voidPtr, uint};
}

llvm::Function *getCAssertFunction(const Loc &loc, llvm::Module &target) {
return getRuntimeFunction(loc, target, getCAssertFunctionName());
}

////////////////////////////////////////////////////////////////////////////////

// extern (D) alias dg_t = int delegate(void*);
Expand Down Expand Up @@ -347,6 +384,11 @@ static void buildRuntimeModule() {
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////

// C assert function
createFwdDecl(LINKc, Type::tvoid, {getCAssertFunctionName()},
getCAssertFunctionParamTypes(), {},
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"},
Expand Down
1 change: 1 addition & 0 deletions gen/runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,6 @@ llvm::Function *getRuntimeFunction(const Loc &loc, llvm::Module &target,

llvm::GlobalVariable *
getRuntimeGlobal(const Loc &loc, llvm::Module &target, const char *name);
llvm::Function *getCAssertFunction(const Loc &loc, llvm::Module &target);

#endif // LDC_GEN_RUNTIME_H
10 changes: 8 additions & 2 deletions gen/statements.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1506,11 +1506,17 @@ class ToIRVisitor : public Visitor {
stmt->loc.toChars());
LOG_SCOPE;

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(
Expand Down
23 changes: 21 additions & 2 deletions gen/toir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1889,8 +1889,16 @@ class ToElemVisitor : public Visitor {
* 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);
Expand Down Expand Up @@ -2339,6 +2347,17 @@ class ToElemVisitor : public Visitor {
e->type->toChars());
LOG_SCOPE;

if (global.params.betterC) {
error(
e->loc,
"array concatenation of expression `%s` requires the GC which is not "
"available with -betterC",
e->toChars());
result =
new DSliceValue(e->type, llvm::UndefValue::get(DtoType(e->type)), llvm::UndefValue::get(DtoType(e->type)));
return;
}

result = DtoCatArrays(e->loc, e->type, e->e1, e->e2);
}

Expand Down
24 changes: 15 additions & 9 deletions gen/tollvm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -463,12 +463,13 @@ LLConstant *DtoConstFP(Type *t, longdouble 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);
Expand All @@ -482,14 +483,19 @@ 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(
return llvm::ConstantExpr::getGetElementPtr(
#if LDC_LLVM_VER >= 307
gvar->getInitializer()->getType(),
#endif
gvar, idxs, true),
Type::tchar->arrayOf());
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());
}

////////////////////////////////////////////////////////////////////////////////
Expand Down
1 change: 1 addition & 0 deletions gen/tollvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ LLConstantInt *DtoConstInt(int i);
LLConstantInt *DtoConstUbyte(unsigned char i);
LLConstant *DtoConstFP(Type *t, longdouble value);

LLConstant *DtoConstCString(const char *);
LLConstant *DtoConstString(const char *);
LLConstant *DtoConstBool(bool);

Expand Down
4 changes: 2 additions & 2 deletions gen/typinf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -737,8 +737,8 @@ void TypeInfoDeclaration_codegen(TypeInfoDeclaration *decl, IRState *p) {

emitTypeMetadata(decl);

// this is a declaration of a builtin __initZ var
if (builtinTypeInfo(decl->tinfo)) {
// check if the definition can be elided
if (global.params.betterC || builtinTypeInfo(decl->tinfo)) {
return;
}

Expand Down
13 changes: 13 additions & 0 deletions tests/codegen/betterC_typeinfo.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Make sure the file can be compiled and linked successfully with -betterC.
// Also test that druntime and Phobos aren't in the linker command line.
// RUN: %ldc -betterC %s -v > %t.log
// RUN: FileCheck %s < %t.log
// CHECK-NOT: druntime-ldc
// CHECK-NOT: phobos2-ldc

struct MyStruct { int a; }

extern (C) void main()
{
auto s = MyStruct();
}
Loading