[svn r233] Added: -oq command line option for writing fully qualified object names.

Added: started support for x86 80bit floating point.
Changed: aggregates passed by value now use the llvm 'byval' parameter attribute, also lays ground work for
using other attributes.
Changed: eliminated a lot more std::vectorS, these showed up pretty much at the top when profiling!
Changed: performed other misc. cleanups.
Changed: halt expression now call the new llvm trap intrinsic instead of an assert(0).
Changed: dstress suite now passes -O0 by default, this only eliminates unreferenced globals, which speeds up
linking quite a bit.
This commit is contained in:
Tomas Lindquist Olsen 2008-06-05 06:38:36 +02:00
parent 1a41b9ef12
commit d03c3a7757
23 changed files with 299 additions and 187 deletions

View file

@ -202,6 +202,7 @@ Usage:\n\
-od<objdir> write object files to directory <objdir>\n\
-of<filename> name output file to <filename>\n\
-op do not strip paths from source file\n\
-oq write object files with fully qualified names\n\
-profile profile runtime performance of generated code\n\
-quiet suppress unnecessary messages\n\
-release compile release version\n\
@ -214,6 +215,7 @@ Usage:\n\
-version=level compile in version code >= level\n\
-version=ident compile in version code identified by ident\n\
-w enable warnings\n\
-fp80 enable 80bit reals on x86 32bit (EXPERIMENTAL)\n\
",
#if WIN32
" @cmdfile read arguments from cmdfile\n"
@ -397,6 +399,8 @@ int main(int argc, char *argv[])
global.params.disassemble = 1;
else if (strcmp(p + 1, "annotate") == 0)
global.params.llvmAnnotate = 1;
else if (strcmp(p + 1, "fp80") == 0)
global.params.useFP80 = 1;
else if (p[1] == 'o')
{
switch (p[2])
@ -423,6 +427,12 @@ int main(int argc, char *argv[])
global.params.preservePaths = 1;
break;
case 'q':
if (p[3])
goto Lerror;
global.params.fqnPaths = 1;
break;
case 0:
error("-o no longer supported, use -of or -od");
break;
@ -691,6 +701,7 @@ int main(int argc, char *argv[])
}
}
bool is_x86 = false;
if (strcmp(global.params.llvmArch,"x86")==0) {
VersionCondition::addPredefinedGlobalIdent("X86");
//VersionCondition::addPredefinedGlobalIdent("LLVM_InlineAsm_X86");
@ -698,6 +709,7 @@ int main(int argc, char *argv[])
global.params.is64bit = false;
tt_arch = "i686";
data_layout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:8";
is_x86 = true;
}
else if (strcmp(global.params.llvmArch,"x86-64")==0) {
VersionCondition::addPredefinedGlobalIdent("X86_64");
@ -740,6 +752,14 @@ int main(int argc, char *argv[])
VersionCondition::addPredefinedGlobalIdent("LLVM64");
}
if (global.params.useFP80) {
if (!is_x86) {
error("the -fp80 option is only valid for the x86 32bit architecture");
fatal();
}
VersionCondition::addPredefinedGlobalIdent("LLVM_X86_FP80");
}
assert(tt_arch != 0);
assert(tt_os != 0);
assert(data_layout != 0);

View file

@ -133,6 +133,8 @@ struct Param
char llvmInline;
char llvmAnnotate;
char *runtimePath;
char useFP80;
char fqnPaths; // use fully qualified object names
};
struct Global

View file

@ -2538,7 +2538,9 @@ Type *TypeFunction::syntaxCopy()
{
Type *treturn = next ? next->syntaxCopy() : NULL;
Arguments *params = Argument::arraySyntaxCopy(parameters);
Type *t = new TypeFunction(params, treturn, varargs, linkage);
TypeFunction *t = new TypeFunction(params, treturn, varargs, linkage);
t->llvmRetInPtr = llvmRetInPtr;
t->llvmUsesThis = llvmUsesThis;
return t;
}
@ -5062,6 +5064,7 @@ Argument::Argument(unsigned storageClass, Type *type, Identifier *ident, Express
this->ident = ident;
this->storageClass = storageClass;
this->defaultArg = defaultArg;
this->llvmByVal = false;
}
Argument *Argument::syntaxCopy()
@ -5070,6 +5073,7 @@ Argument *Argument::syntaxCopy()
type ? type->syntaxCopy() : NULL,
ident,
defaultArg ? defaultArg->syntaxCopy() : NULL);
a->llvmByVal = llvmByVal;
return a;
}

View file

@ -681,6 +681,9 @@ struct Argument : Object
static void argsToDecoBuffer(OutBuffer *buf, Arguments *arguments);
static size_t dim(Arguments *arguments);
static Argument *getNth(Arguments *arguments, size_t nth, size_t *pn = NULL);
// LLVMDC
bool llvmByVal;
};
extern int PTRSIZE;

View file

@ -86,15 +86,8 @@ DValue* DtoAAIndex(Type* type, DValue* aa, DValue* key)
LLValue* pkey = to_pkey(key);
pkey = DtoBitCast(pkey, funcTy->getParamType(3));
// build arg vector
LLSmallVector<LLValue*, 4> args;
args.push_back(aaval);
args.push_back(keyti);
args.push_back(valsize);
args.push_back(pkey);
// call runtime
LLValue* ret = gIR->ir->CreateCall(func, args.begin(), args.end(), "aa.index");
LLValue* ret = gIR->ir->CreateCall4(func, aaval, keyti, valsize, pkey, "aa.index");
// cast return value
const LLType* targettype = getPtrToType(DtoType(type));
@ -131,14 +124,8 @@ DValue* DtoAAIn(Type* type, DValue* aa, DValue* key)
LLValue* pkey = to_pkey(key);
pkey = DtoBitCast(pkey, funcTy->getParamType(2));
// build arg vector
LLSmallVector<LLValue*, 3> args;
args.push_back(aaval);
args.push_back(keyti);
args.push_back(pkey);
// call runtime
LLValue* ret = gIR->ir->CreateCall(func, args.begin(), args.end(), "aa.in");
LLValue* ret = gIR->ir->CreateCall3(func, aaval, keyti, pkey, "aa.in");
// cast return value
const LLType* targettype = DtoType(type);

View file

@ -184,7 +184,7 @@ void DtoArrayInit(LLValue* ptr, LLValue* dim, LLValue* val)
Logger::cout() << "array: " << *ptr << " dim: " << *dim << " val: " << *val << '\n';
std::vector<LLValue*> args;
LLSmallVector<LLValue*, 4> args;
args.push_back(ptr);
args.push_back(dim);
args.push_back(val);
@ -424,12 +424,11 @@ void DtoArrayCopySlices(DSliceValue* dst, DSliceValue* src)
LLValue* srcarr = DtoBitCast(get_slice_ptr(src,sz2),arrty);
llvm::Function* fn = (global.params.is64bit) ? LLVM_DeclareMemCpy64() : LLVM_DeclareMemCpy32();
std::vector<LLValue*> llargs;
llargs.resize(4);
LLSmallVector<LLValue*, 4> llargs(4);
llargs[0] = dstarr;
llargs[1] = srcarr;
llargs[2] = sz1;
llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
llargs[3] = DtoConstInt(0);
llvm::CallInst::Create(fn, llargs.begin(), llargs.end(), "", gIR->scopebb());
}
@ -444,12 +443,11 @@ void DtoArrayCopyToSlice(DSliceValue* dst, DValue* src)
LLValue* srcarr = DtoBitCast(DtoArrayPtr(src),arrty);
llvm::Function* fn = (global.params.is64bit) ? LLVM_DeclareMemCpy64() : LLVM_DeclareMemCpy32();
std::vector<LLValue*> llargs;
llargs.resize(4);
LLSmallVector<LLValue*, 4> llargs(4);
llargs[0] = dstarr;
llargs[1] = srcarr;
llargs[2] = sz1;
llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
llargs[3] = DtoConstInt(0);
llvm::CallInst::Create(fn, llargs.begin(), llargs.end(), "", gIR->scopebb());
}
@ -467,12 +465,11 @@ void DtoStaticArrayCopy(LLValue* dst, LLValue* src)
LLValue* srcarr = DtoBitCast(src,arrty);
llvm::Function* fn = (global.params.is64bit) ? LLVM_DeclareMemCpy64() : LLVM_DeclareMemCpy32();
std::vector<LLValue*> llargs;
llargs.resize(4);
LLSmallVector<LLValue*,4> llargs(4);
llargs[0] = dstarr;
llargs[1] = srcarr;
llargs[2] = n;
llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
llargs[3] = DtoConstInt(0);
llvm::CallInst::Create(fn, llargs.begin(), llargs.end(), "", gIR->scopebb());
}
@ -480,14 +477,8 @@ void DtoStaticArrayCopy(LLValue* dst, LLValue* src)
//////////////////////////////////////////////////////////////////////////////////////////
LLConstant* DtoConstSlice(LLConstant* dim, LLConstant* ptr)
{
std::vector<const LLType*> types;
types.push_back(dim->getType());
types.push_back(ptr->getType());
const llvm::StructType* type = llvm::StructType::get(types);
std::vector<LLConstant*> values;
values.push_back(dim);
values.push_back(ptr);
return llvm::ConstantStruct::get(type,values);
LLConstant* values[2] = { dim, ptr };
return llvm::ConstantStruct::get(values, 2);
}
//////////////////////////////////////////////////////////////////////////////////////////
@ -496,15 +487,21 @@ DSliceValue* DtoNewDynArray(Type* arrayType, DValue* dim, bool defaultInit)
Logger::println("DtoNewDynArray : %s", arrayType->toChars());
LOG_SCOPE;
// typeinfo arg
LLValue* arrayTypeInfo = DtoTypeInfoOf(arrayType);
// dim arg
assert(DtoType(dim->getType()) == DtoSize_t());
LLValue* arrayLen = dim->getRVal();
// get runtime function
bool zeroInit = arrayType->toBasetype()->nextOf()->isZeroInit();
llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, zeroInit ? "_d_newarrayT" : "_d_newarrayiT" );
LLSmallVector<LLValue*,2> args;
args.push_back(DtoTypeInfoOf(arrayType));
assert(DtoType(dim->getType()) == DtoSize_t());
args.push_back(dim->getRVal());
// call allocator
LLValue* newptr = gIR->ir->CreateCall2(fn, arrayTypeInfo, arrayLen, ".gc_mem");
LLValue* newptr = gIR->ir->CreateCall(fn, args.begin(), args.end(), ".gc_mem");
// cast to wanted type
const LLType* dstType = DtoType(arrayType)->getContainedType(1);
if (newptr->getType() != dstType)
newptr = DtoBitCast(newptr, dstType, ".gc_mem");
@ -518,7 +515,7 @@ DSliceValue* DtoNewDynArray(Type* arrayType, DValue* dim, bool defaultInit)
}
#endif
return new DSliceValue(arrayType, args[1], newptr);
return new DSliceValue(arrayType, arrayLen, newptr);
}
//////////////////////////////////////////////////////////////////////////////////////////
@ -542,6 +539,7 @@ DSliceValue* DtoResizeDynArray(Type* arrayType, DValue* array, DValue* newdim)
args.push_back(DtoTypeInfoOf(arrayType));
args.push_back(newdim->getRVal());
args.push_back(DtoArrayLen(array));
LLValue* arrPtr = DtoArrayPtr(array);
Logger::cout() << "arrPtr = " << *arrPtr << '\n';
args.push_back(DtoBitCast(arrPtr, fn->getFunctionType()->getParamType(3), "tmp"));
@ -734,7 +732,7 @@ static LLValue* DtoArrayEqCmp_impl(const char* func, DValue* l, DValue* r, bool
Type* r_ty = DtoDType(r->getType());
assert(l_ty->next == r_ty->next);
if ((l_ty->ty == Tsarray) || (r_ty->ty == Tsarray)) {
Type* a_ty = new Type(Tarray, l_ty->next);
Type* a_ty = l_ty->next->arrayOf();
if (l_ty->ty == Tsarray)
l = DtoCastArray(l, a_ty);
if (r_ty->ty == Tsarray)
@ -774,7 +772,7 @@ static LLValue* DtoArrayEqCmp_impl(const char* func, DValue* l, DValue* r, bool
const LLType* pt = fn->getFunctionType()->getParamType(0);
std::vector<LLValue*> args;
LLSmallVector<LLValue*, 3> args;
Logger::cout() << "bitcasting to " << *pt << '\n';
Logger::cout() << *lmem << '\n';
Logger::cout() << *rmem << '\n';
@ -799,9 +797,6 @@ static LLValue* DtoArrayEqCmp_impl(const char* func, DValue* l, DValue* r, bool
//////////////////////////////////////////////////////////////////////////////////////////
LLValue* DtoArrayEquals(TOK op, DValue* l, DValue* r)
{
llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_adEq");
assert(fn);
LLValue* res = DtoArrayEqCmp_impl("_adEq", l, r, true);
if (op == TOKnotequal)
res = gIR->ir->CreateNot(res, "tmp");
@ -883,7 +878,7 @@ LLValue* DtoArrayCastLength(LLValue* len, const LLType* elemty, const LLType* ne
if (esz == nsz)
return len;
std::vector<LLValue*> args;
LLSmallVector<LLValue*, 3> args;
args.push_back(len);
args.push_back(llvm::ConstantInt::get(DtoSize_t(), esz, false));
args.push_back(llvm::ConstantInt::get(DtoSize_t(), nsz, false));

View file

@ -796,9 +796,7 @@ DValue* DtoNewClass(TypeClass* tc, NewExp* newexp)
else
{
llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_newclass");
std::vector<LLValue*> args;
args.push_back(tc->sym->ir.irStruct->classInfo);
mem = gIR->ir->CreateCall(fn, args.begin(), args.end(), "newclass_gc_alloc");
mem = gIR->ir->CreateCall(fn, tc->sym->ir.irStruct->classInfo, "newclass_gc_alloc");
mem = DtoBitCast(mem, DtoType(tc), "newclass_gc");
}
@ -898,6 +896,8 @@ DValue* DtoCallClassCtor(TypeClass* type, CtorDeclaration* ctor, Array* argument
llvm::Function* fn = ctor->ir.irFunc->func;
TypeFunction* tf = (TypeFunction*)DtoDType(ctor->type);
llvm::PAListPtr palist;
std::vector<LLValue*> ctorargs;
ctorargs.push_back(mem);
for (size_t i=0; i<arguments->dim; ++i)
@ -910,9 +910,12 @@ DValue* DtoCallClassCtor(TypeClass* type, CtorDeclaration* ctor, Array* argument
if (a->getType() != aty)
a = DtoBitCast(a, aty);
ctorargs.push_back(a);
if (fnarg && fnarg->llvmByVal)
palist = palist.addAttr(i+2, llvm::ParamAttr::ByVal); // return,this is 2
}
llvm::CallInst* call = llvm::CallInst::Create(fn, ctorargs.begin(), ctorargs.end(), "tmp", gIR->scopebb());
call->setCallingConv(DtoCallingConv(LINKd));
call->setParamAttrs(palist);
return new DImValue(type, call, false);
}
@ -997,24 +1000,22 @@ DValue* DtoDynamicCastObject(DValue* val, Type* _to)
std::vector<LLValue*> args;
// Object o
LLValue* tmp = val->getRVal();
tmp = DtoBitCast(tmp, funcTy->getParamType(0));
args.push_back(tmp);
assert(funcTy->getParamType(0) == tmp->getType());
LLValue* obj = val->getRVal();
obj = DtoBitCast(obj, funcTy->getParamType(0));
assert(funcTy->getParamType(0) == obj->getType());
// ClassInfo c
TypeClass* to = (TypeClass*)DtoDType(_to);
DtoForceDeclareDsymbol(to->sym);
assert(to->sym->ir.irStruct->classInfo);
tmp = to->sym->ir.irStruct->classInfo;
LLValue* cinfo = to->sym->ir.irStruct->classInfo;
// unfortunately this is needed as the implementation of object differs somehow from the declaration
// this could happen in user code as well :/
tmp = DtoBitCast(tmp, funcTy->getParamType(1));
args.push_back(tmp);
assert(funcTy->getParamType(1) == tmp->getType());
cinfo = DtoBitCast(cinfo, funcTy->getParamType(1));
assert(funcTy->getParamType(1) == cinfo->getType());
// call it
LLValue* ret = gIR->ir->CreateCall(func, args.begin(), args.end(), "tmp");
LLValue* ret = gIR->ir->CreateCall2(func, obj, cinfo, "tmp");
// cast return value
ret = DtoBitCast(ret, DtoType(_to));
@ -1064,22 +1065,20 @@ DValue* DtoDynamicCastInterface(DValue* val, Type* _to)
std::vector<LLValue*> args;
// void* p
LLValue* tmp = val->getRVal();
tmp = DtoBitCast(tmp, funcTy->getParamType(0));
args.push_back(tmp);
LLValue* ptr = val->getRVal();
ptr = DtoBitCast(ptr, funcTy->getParamType(0));
// ClassInfo c
TypeClass* to = (TypeClass*)DtoDType(_to);
DtoForceDeclareDsymbol(to->sym);
assert(to->sym->ir.irStruct->classInfo);
tmp = to->sym->ir.irStruct->classInfo;
LLValue* cinfo = to->sym->ir.irStruct->classInfo;
// unfortunately this is needed as the implementation of object differs somehow from the declaration
// this could happen in user code as well :/
tmp = DtoBitCast(tmp, funcTy->getParamType(1));
args.push_back(tmp);
cinfo = DtoBitCast(cinfo, funcTy->getParamType(1));
// call it
LLValue* ret = gIR->ir->CreateCall(func, args.begin(), args.end(), "tmp");
LLValue* ret = gIR->ir->CreateCall2(func, ptr, cinfo, "tmp");
// cast return value
ret = DtoBitCast(ret, DtoType(_to));
@ -1127,7 +1126,7 @@ void ClassDeclaration::offsetToIndex(Type* t, unsigned os, std::vector<unsigned>
//////////////////////////////////////////////////////////////////////////////////////////
LLValue* DtoIndexClass(LLValue* ptr, ClassDeclaration* cd, Type* t, unsigned os, std::vector<unsigned>& idxs)
LLValue* DtoIndexClass(LLValue* ptr, ClassDeclaration* cd, Type* t, unsigned os, DStructIndexVector& idxs)
{
Logger::println("checking for offset %u type %s:", os, t->toChars());
LOG_SCOPE;
@ -1157,7 +1156,7 @@ LLValue* DtoIndexClass(LLValue* ptr, ClassDeclaration* cd, Type* t, unsigned os,
Logger::println("found %s %s", vdtype->toChars(), vd->toChars());
idxs.push_back(vd->ir.irField->index + dataoffset);
//Logger::cout() << "indexing: " << *ptr << '\n';
ptr = DtoGEP(ptr, idxs, "tmp");
ptr = DtoGEPi(ptr, idxs, "tmp");
if (ptr->getType() != llt)
ptr = gIR->ir->CreateBitCast(ptr, llt, "tmp");
//Logger::cout() << "indexing: " << *ptr << '\n';
@ -1172,18 +1171,18 @@ LLValue* DtoIndexClass(LLValue* ptr, ClassDeclaration* cd, Type* t, unsigned os,
idxs.push_back(vd->ir.irField->index + dataoffset);
if (vd->ir.irField->indexOffset) {
Logger::println("has union field offset");
ptr = DtoGEP(ptr, idxs, "tmp");
ptr = DtoGEPi(ptr, idxs, "tmp");
if (ptr->getType() != llt)
ptr = gIR->ir->CreateBitCast(ptr, llt, "tmp");
ptr = llvm::GetElementPtrInst::Create(ptr, DtoConstUint(vd->ir.irField->indexOffset), "tmp", gIR->scopebb());
std::vector<unsigned> tmp;
DStructIndexVector tmp;
return DtoIndexStruct(ptr, ssd, t, os-vd->offset, tmp);
}
else {
const LLType* sty = getPtrToType(DtoType(vd->type));
if (ptr->getType() != sty) {
ptr = gIR->ir->CreateBitCast(ptr, sty, "tmp");
std::vector<unsigned> tmp;
DStructIndexVector tmp;
return DtoIndexStruct(ptr, ssd, t, os-vd->offset, tmp);
}
else {

View file

@ -1,6 +1,8 @@
#ifndef LLVMDC_GEN_CLASSES_H
#define LLVMDC_GEN_CLASSES_H
#include "gen/structs.h"
/**
* Resolves the llvm type for a class declaration
*/
@ -35,7 +37,7 @@ DValue* DtoDynamicCastObject(DValue* val, Type* to);
DValue* DtoCastInterfaceToObject(DValue* val, Type* to);
DValue* DtoDynamicCastInterface(DValue* val, Type* to);
LLValue* DtoIndexClass(LLValue* ptr, ClassDeclaration* cd, Type* t, unsigned os, std::vector<unsigned>& idxs);
LLValue* DtoIndexClass(LLValue* ptr, ClassDeclaration* cd, Type* t, unsigned os, DStructIndexVector& idxs);
LLValue* DtoVirtualFunctionPointer(DValue* inst, FuncDeclaration* fdecl);

View file

@ -28,10 +28,13 @@ const LLType* DtoComplexBaseType(Type* t)
TY ty = DtoDType(t)->ty;
const LLType* base;
if (ty == Tcomplex32) {
return llvm::Type::FloatTy;
return LLType::FloatTy;
}
else if (ty == Tcomplex64 || ty == Tcomplex80) {
return llvm::Type::DoubleTy;
else if (ty == Tcomplex64) {
return LLType::DoubleTy;
}
else if (ty == Tcomplex80) {
return (global.params.useFP80) ? LLType::X86_FP80Ty : LLType::DoubleTy;
}
else {
assert(0);
@ -60,49 +63,25 @@ LLConstant* DtoConstComplex(Type* _ty, long double re, long double im)
llvm::ConstantFP* fre;
llvm::ConstantFP* fim;
const LLType* base;
Type* base = 0;
if (ty == Tcomplex32) {
fre = DtoConstFP(Type::tfloat32, re);
fim = DtoConstFP(Type::tfloat32, im);
base = llvm::Type::FloatTy;
base = Type::tfloat32;
}
else if (ty == Tcomplex64 || ty == Tcomplex80) {
fre = DtoConstFP(Type::tfloat64, re);
fim = DtoConstFP(Type::tfloat64, im);
base = llvm::Type::DoubleTy;
else if (ty == Tcomplex64) {
base = Type::tfloat64;
}
else if (ty == Tcomplex80) {
base = (global.params.useFP80) ? Type::tfloat80 : Type::tfloat64;
}
else
assert(0);
std::vector<LLConstant*> inits;
inits.push_back(fre);
inits.push_back(fim);
inits.push_back(DtoConstFP(base, re));
inits.push_back(DtoConstFP(base, im));
return llvm::ConstantStruct::get(DtoComplexType(_ty), inits);
}
LLConstant* DtoUndefComplex(Type* _ty)
{
assert(0);
TY ty = DtoDType(_ty)->ty;
const LLType* base;
if (ty == Tcomplex32) {
base = llvm::Type::FloatTy;
}
else if (ty == Tcomplex64 || ty == Tcomplex80) {
base = llvm::Type::DoubleTy;
}
else
assert(0);
std::vector<LLConstant*> inits;
inits.push_back(llvm::UndefValue::get(base));
inits.push_back(llvm::UndefValue::get(base));
const llvm::VectorType* vt = llvm::VectorType::get(base, 2);
return llvm::ConstantVector::get(vt, inits);
}
//////////////////////////////////////////////////////////////////////////////////////////
LLValue* DtoRealPart(DValue* val)
@ -135,9 +114,11 @@ DValue* DtoComplex(Type* to, DValue* val)
LLConstant* undef = llvm::UndefValue::get(base);
LLConstant* zero;
if (ty == Tfloat32 || ty == Timaginary32 || ty == Tcomplex32)
zero = llvm::ConstantFP::get(llvm::APFloat(0.0f));
else if (ty == Tfloat64 || ty == Timaginary64 || ty == Tcomplex64 || ty == Tfloat80 || ty == Timaginary80 || ty == Tcomplex80)
zero = llvm::ConstantFP::get(llvm::APFloat(0.0));
zero = LLConstant::getNullValue(DtoType(Type::tfloat32)); // llvm::ConstantFP::get(llvm::APFloat(0.0f));
else if (ty == Tfloat64 || ty == Timaginary64 || ty == Tcomplex64)
zero = LLConstant::getNullValue(DtoType(Type::tfloat64));
else if (ty == Tfloat80 || ty == Timaginary80 || ty == Tcomplex80)
zero = LLConstant::getNullValue(DtoType((global.params.useFP80)?Type::tfloat80:Type::tfloat64));
if (t->isimaginary()) {
return new DComplexValue(to, zero, val->getRVal());

View file

@ -2,11 +2,10 @@
#define LLVMDC_GEN_COMPLEX_H
const llvm::StructType* DtoComplexType(Type* t);
const llvm::Type* DtoComplexBaseType(Type* t);
const LLType* DtoComplexBaseType(Type* t);
LLConstant* DtoConstComplex(Type* t, LLConstant* re, LLConstant* im);
LLConstant* DtoConstComplex(Type* t, long double re, long double im);
LLConstant* DtoUndefComplex(Type* _ty);
LLConstant* DtoComplexShuffleMask(unsigned a, unsigned b);

View file

@ -51,7 +51,7 @@ const llvm::FunctionType* DtoFunctionType(Type* type, const LLType* thistype, bo
else {
assert(rt);
Type* rtfin = DtoDType(rt);
if (DtoIsPassedByRef(rt)) {
if (DtoIsReturnedInArg(rt)) {
rettype = getPtrToType(DtoType(rt));
actualRettype = llvm::Type::VoidTy;
f->llvmRetInPtr = retinptr = true;
@ -94,22 +94,30 @@ const llvm::FunctionType* DtoFunctionType(Type* type, const LLType* thistype, bo
size_t n = Argument::dim(f->parameters);
int nbyval = 0;
llvm::PAListPtr palist;
for (int i=0; i < n; ++i) {
Argument* arg = Argument::getNth(f->parameters, i);
// ensure scalar
Type* argT = DtoDType(arg->type);
assert(argT);
bool refOrOut = ((arg->storageClass & STCref) || (arg->storageClass & STCout));
const LLType* at = DtoType(argT);
if (isaStruct(at)) {
Logger::println("struct param");
paramvec.push_back(getPtrToType(at));
arg->llvmByVal = !refOrOut;
}
else if (isaArray(at)) {
Logger::println("sarray param");
assert(argT->ty == Tsarray);
//paramvec.push_back(getPtrToType(at->getContainedType(0)));
paramvec.push_back(getPtrToType(at));
arg->llvmByVal = !refOrOut;
}
else if (llvm::isa<llvm::OpaqueType>(at)) {
Logger::println("opaque param");
@ -117,7 +125,7 @@ const llvm::FunctionType* DtoFunctionType(Type* type, const LLType* thistype, bo
paramvec.push_back(getPtrToType(at));
}
else {
if ((arg->storageClass & STCref) || (arg->storageClass & STCout)) {
if (refOrOut) {
Logger::println("by ref param");
at = getPtrToType(at);
}
@ -126,8 +134,13 @@ const llvm::FunctionType* DtoFunctionType(Type* type, const LLType* thistype, bo
}
paramvec.push_back(at);
}
if (arg->llvmByVal)
nbyval++;
}
//warning("set %d byval args for type: %s", nbyval, f->toChars());
// construct function type
bool isvararg = !(typesafeVararg || arrayVararg) && f->varargs;
llvm::FunctionType* functype = llvm::FunctionType::get(actualRettype, paramvec, isvararg);
@ -135,10 +148,7 @@ const llvm::FunctionType* DtoFunctionType(Type* type, const LLType* thistype, bo
f->llvmRetInPtr = retinptr;
f->llvmUsesThis = usesthis;
//if (!f->ir.type)
f->ir.type = new llvm::PATypeHolder(functype);
//else
//assert(functype == f->ir.type->get());
return functype;
}
@ -378,6 +388,43 @@ void DtoDeclareFunction(FuncDeclaration* fdecl)
fdecl->ir.irFunc->func = func;
assert(llvm::isa<llvm::FunctionType>(f->ir.type->get()));
// parameter attributes
if (f->parameters)
{
int llidx = 1;
if (f->llvmRetInPtr) ++llidx;
if (f->llvmUsesThis) ++llidx;
if (f->linkage == LINKd && f->varargs == 1)
llidx += 2;
int funcNumArgs = func->getArgumentList().size();
std::vector<llvm::ParamAttrsWithIndex> attrs;
int k = 0;
int nbyval = 0;
for (; llidx <= funcNumArgs && f->parameters->dim > k; ++llidx,++k)
{
Argument* fnarg = (Argument*)f->parameters->data[k];
assert(fnarg);
if (fnarg->llvmByVal)
{
llvm::ParamAttrsWithIndex PAWI;
PAWI.Index = llidx;
PAWI.Attrs = llvm::ParamAttr::ByVal;
attrs.push_back(PAWI);
nbyval++;
}
}
//warning("set %d byval args for function: %s", nbyval, func->getName().c_str());
if (nbyval) {
llvm::PAListPtr palist = llvm::PAListPtr::get(attrs.begin(), attrs.end());
func->setParamAttrs(palist);
}
}
// main
if (fdecl->isMain()) {
gIR->mainFunc = func;
@ -775,19 +822,14 @@ DValue* DtoArgument(Argument* fnarg, Expression* argexp)
else
arg = new DImValue(argexp->type, arg->getRVal(), false);
}
// aggregate arg
else if (DtoIsPassedByRef(argexp->type))
// byval arg, but expr has no storage yet
else if (DtoIsPassedByRef(argexp->type) && (arg->isSlice() || arg->isComplex() || arg->isNull()))
{
LLValue* alloc = new llvm::AllocaInst(DtoType(argexp->type), "tmpparam", gIR->topallocapoint());
DVarValue* vv = new DVarValue(argexp->type, alloc, true);
DtoAssign(vv, arg);
arg = vv;
}
// normal arg (basic/value type)
else
{
// nothing to do
}
return arg;
}

View file

@ -92,7 +92,7 @@ void ReturnStatement::toIR(IRState* p)
emit_finallyblocks(p, enclosingtryfinally, NULL);
if (gIR->func()->inVolatile) {
if (f->inVolatile) {
// store-load barrier
DtoMemoryBarrier(false, false, true, false);
}
@ -128,7 +128,7 @@ void ReturnStatement::toIR(IRState* p)
}
else
{
if (p->topfunc()->getReturnType() == llvm::Type::VoidTy) {
assert(p->topfunc()->getReturnType() == llvm::Type::VoidTy);
emit_finallyblocks(p, enclosingtryfinally, NULL);
if (gIR->func()->inVolatile) {
@ -139,11 +139,6 @@ void ReturnStatement::toIR(IRState* p)
if (global.params.symdebug) DtoDwarfFuncEnd(p->func()->decl);
llvm::ReturnInst::Create(p->scopebb());
}
else {
assert(0); // why should this ever happen?
new llvm::UnreachableInst(p->scopebb());
}
}
}
//////////////////////////////////////////////////////////////////////////////
@ -616,11 +611,10 @@ static LLValue* call_string_switch_runtime(llvm::GlobalVariable* table, Expressi
}
llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, fname);
std::vector<LLValue*> args;
Logger::cout() << *table->getType() << '\n';
Logger::cout() << *fn->getFunctionType()->getParamType(0) << '\n';
assert(table->getType() == fn->getFunctionType()->getParamType(0));
args.push_back(table);
DValue* val = e->toElem(gIR);
LLValue* llval;
@ -636,9 +630,8 @@ static LLValue* call_string_switch_runtime(llvm::GlobalVariable* table, Expressi
llval = val->getRVal();
}
assert(llval->getType() == fn->getFunctionType()->getParamType(1));
args.push_back(llval);
return gIR->ir->CreateCall(fn, args.begin(), args.end(), "tmp");
return gIR->ir->CreateCall2(fn, table, llval, "tmp");
}
void SwitchStatement::toIR(IRState* p)

View file

@ -105,7 +105,7 @@ LLConstant* DtoConstStructInitializer(StructInitializer* si)
//////////////////////////////////////////////////////////////////////////////////////////
LLValue* DtoIndexStruct(LLValue* ptr, StructDeclaration* sd, Type* t, unsigned os, std::vector<unsigned>& idxs)
LLValue* DtoIndexStruct(LLValue* ptr, StructDeclaration* sd, Type* t, unsigned os, DStructIndexVector& idxs)
{
Logger::println("checking for offset %u type %s:", os, t->toChars());
LOG_SCOPE;
@ -127,7 +127,7 @@ LLValue* DtoIndexStruct(LLValue* ptr, StructDeclaration* sd, Type* t, unsigned o
assert(vd->ir.irField->index >= 0);
if (os == vd->offset && vdtype == t) {
idxs.push_back(vd->ir.irField->index);
ptr = DtoGEP(ptr, idxs, "tmp");
ptr = DtoGEPi(ptr, idxs, "tmp");
if (ptr->getType() != llt)
ptr = gIR->ir->CreateBitCast(ptr, llt, "tmp");
if (vd->ir.irField->indexOffset)
@ -140,18 +140,18 @@ LLValue* DtoIndexStruct(LLValue* ptr, StructDeclaration* sd, Type* t, unsigned o
idxs.push_back(vd->ir.irField->index);
if (vd->ir.irField->indexOffset) {
Logger::println("has union field offset");
ptr = DtoGEP(ptr, idxs, "tmp");
ptr = DtoGEPi(ptr, idxs, "tmp");
if (ptr->getType() != llt)
ptr = DtoBitCast(ptr, llt);
ptr = llvm::GetElementPtrInst::Create(ptr, DtoConstUint(vd->ir.irField->indexOffset), "tmp", gIR->scopebb());
std::vector<unsigned> tmp;
DStructIndexVector tmp;
return DtoIndexStruct(ptr, ssd, t, os-vd->offset, tmp);
}
else {
const LLType* sty = getPtrToType(DtoType(vd->type));
if (ptr->getType() != sty) {
ptr = DtoBitCast(ptr, sty);
std::vector<unsigned> tmp;
DStructIndexVector tmp;
return DtoIndexStruct(ptr, ssd, t, os-vd->offset, tmp);
}
else {

View file

@ -30,7 +30,8 @@ void DtoConstInitStruct(StructDeclaration* sd);
*/
void DtoDefineStruct(StructDeclaration* sd);
LLValue* DtoIndexStruct(LLValue* ptr, StructDeclaration* sd, Type* t, unsigned os, std::vector<unsigned>& idxs);
typedef LLSmallVector<unsigned, 3> DStructIndexVector;
LLValue* DtoIndexStruct(LLValue* ptr, StructDeclaration* sd, Type* t, unsigned os, DStructIndexVector& idxs);
struct DUnionField
{

View file

@ -196,7 +196,7 @@ void DtoDwarfFuncEnd(FuncDeclaration* fd)
void DtoDwarfStopPoint(unsigned ln)
{
std::vector<LLValue*> args;
LLSmallVector<LLValue*,3> args;
args.push_back(DtoConstUint(ln));
args.push_back(DtoConstUint(0));
FuncDeclaration* fd = gIR->func()->decl;

View file

@ -618,7 +618,7 @@ DValue* AddExp::toElem(IRState* p)
llvm::ConstantInt* cofs = llvm::cast<llvm::ConstantInt>(r->isConst()->c);
TypeStruct* ts = (TypeStruct*)e1next;
std::vector<unsigned> offsets;
DStructIndexVector offsets;
LLValue* v = DtoIndexStruct(l->getRVal(), ts->sym, t->next, cofs->getZExtValue(), offsets);
return new DFieldValue(type, v, true);
}
@ -1018,7 +1018,11 @@ DValue* CallExp::toElem(IRState* p)
bool isInPlace = false;
// attrs
llvm::PAListPtr palist;
// hidden struct return arguments
// TODO: use sret param attr
if (retinptr) {
if (topexp && topexp->e2 == this) {
assert(topexp->v);
@ -1167,6 +1171,10 @@ DValue* CallExp::toElem(IRState* p)
Argument* fnarg = Argument::getNth(tf->parameters, i);
DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]);
llargs[j] = argval->getRVal();
#if USE_BYVAL
if (fnarg->llvmByVal)
palist = palist.addAttr(j, llvm::ParamAttr::ByVal);
#endif
j++;
}
@ -1187,6 +1195,11 @@ DValue* CallExp::toElem(IRState* p)
llargs[j] = DtoBitCast(llargs[j], llfnty->getParamType(j));
}
#if USE_BYVAL
if (fnarg && fnarg->llvmByVal)
palist = palist.addAttr(j+1, llvm::ParamAttr::ByVal);
#endif
// this hack is necessary :/
if (dfn && dfn->func && dfn->func->runTimeHack) {
if (llfnty->getParamType(j) != NULL) {
@ -1245,6 +1258,9 @@ DValue* CallExp::toElem(IRState* p)
call->setCallingConv(DtoCallingConv(dlink));
}
// param attrs
call->setParamAttrs(palist);
return new DImValue(type, retllval, isInPlace);
}
@ -1311,7 +1327,7 @@ DValue* SymOffExp::toElem(IRState* p)
varmem = p->ir->CreateBitCast(llvalue, llt, "tmp");
}
else {
std::vector<unsigned> dst;
DStructIndexVector dst;
varmem = DtoIndexStruct(llvalue,vdt->sym, tnext, offset, dst);
}
}
@ -1429,7 +1445,7 @@ DValue* DotVarExp::toElem(IRState* p)
LLValue* src = l->getRVal();
std::vector<unsigned> vdoffsets;
DStructIndexVector vdoffsets;
arrptr = DtoIndexStruct(src, ts->sym, vd->type, vd->offset, vdoffsets);
}
else if (e1type->ty == Tclass) {
@ -1438,7 +1454,7 @@ DValue* DotVarExp::toElem(IRState* p)
LLValue* src = l->getRVal();
std::vector<unsigned> vdoffsets;
DStructIndexVector vdoffsets;
arrptr = DtoIndexClass(src, tc->sym, vd->type, vd->offset, vdoffsets);
/*std::vector<unsigned> vdoffsets(1,0);
@ -2255,7 +2271,8 @@ DValue* HaltExp::toElem(IRState* p)
Logger::print("HaltExp::toElem: %s | %s\n", toChars(), type->toChars());
LOG_SCOPE;
DtoAssert(&loc, NULL);
// call the new (?) trap intrinsic
p->ir->CreateCall(GET_INTRINSIC_DECL(trap),"");
new llvm::UnreachableInst(p->scopebb());
return 0;

View file

@ -26,6 +26,13 @@ bool DtoIsPassedByRef(Type* type)
return (t == Tstruct || t == Tarray || t == Tdelegate || t == Tsarray || typ->iscomplex());
}
bool DtoIsReturnedInArg(Type* type)
{
Type* typ = DtoDType(type);
TY t = typ->ty;
return (t == Tstruct || t == Tarray || t == Tdelegate || t == Tsarray || typ->iscomplex());
}
Type* DtoDType(Type* t)
{
if (t->ty == Ttypedef) {
@ -67,9 +74,10 @@ const LLType* DtoType(Type* t)
return llvm::Type::FloatTy;
case Tfloat64:
case Timaginary64:
return llvm::Type::DoubleTy;
case Tfloat80:
case Timaginary80:
return llvm::Type::DoubleTy;
return (global.params.useFP80) ? llvm::Type::X86_FP80Ty : llvm::Type::DoubleTy;
// complex
case Tcomplex32:
@ -590,46 +598,42 @@ DValue* DtoInitializer(Initializer* init)
//////////////////////////////////////////////////////////////////////////////////////////
LLValue* DtoGEP(LLValue* ptr, LLValue* i0, LLValue* i1, const std::string& var, llvm::BasicBlock* bb)
LLValue* DtoGEP(LLValue* ptr, LLValue* i0, LLValue* i1, const char* var, llvm::BasicBlock* bb)
{
std::vector<LLValue*> v(2);
LLSmallVector<LLValue*,2> v(2);
v[0] = i0;
v[1] = i1;
Logger::cout() << "DtoGEP: " << *ptr << ", " << *i0 << ", " << *i1 << '\n';
return llvm::GetElementPtrInst::Create(ptr, v.begin(), v.end(), var, bb?bb:gIR->scopebb());
}
//////////////////////////////////////////////////////////////////////////////////////////
LLValue* DtoGEP(LLValue* ptr, const std::vector<unsigned>& src, const std::string& var, llvm::BasicBlock* bb)
LLValue* DtoGEPi(LLValue* ptr, const DStructIndexVector& src, const char* var, llvm::BasicBlock* bb)
{
size_t n = src.size();
std::vector<LLValue*> dst(n, NULL);
//std::ostream& ostr = Logger::cout();
//ostr << "indices for '" << *ptr << "':";
for (size_t i=0; i<n; ++i)
{
//ostr << ' ' << i;
dst[i] = llvm::ConstantInt::get(llvm::Type::Int32Ty, src[i], false);
}
//ostr << '\n';*/
LLSmallVector<LLValue*, 3> dst(n);
size_t j=0;
for (DStructIndexVector::const_iterator i=src.begin(); i!=src.end(); ++i)
dst[j++] = DtoConstUint(*i);
return llvm::GetElementPtrInst::Create(ptr, dst.begin(), dst.end(), var, bb?bb:gIR->scopebb());
}
//////////////////////////////////////////////////////////////////////////////////////////
LLValue* DtoGEPi(LLValue* ptr, unsigned i, const std::string& var, llvm::BasicBlock* bb)
LLValue* DtoGEPi(LLValue* ptr, unsigned i, const char* var, llvm::BasicBlock* bb)
{
return llvm::GetElementPtrInst::Create(ptr, llvm::ConstantInt::get(llvm::Type::Int32Ty, i, false), var, bb?bb:gIR->scopebb());
}
//////////////////////////////////////////////////////////////////////////////////////////
LLValue* DtoGEPi(LLValue* ptr, unsigned i0, unsigned i1, const std::string& var, llvm::BasicBlock* bb)
LLValue* DtoGEPi(LLValue* ptr, unsigned i0, unsigned i1, const char* var, llvm::BasicBlock* bb)
{
std::vector<LLValue*> v(2);
v[0] = llvm::ConstantInt::get(llvm::Type::Int32Ty, i0, false);
v[1] = llvm::ConstantInt::get(llvm::Type::Int32Ty, i1, false);
LLSmallVector<LLValue*,2> v(2);
v[0] = DtoConstUint(i0);
v[1] = DtoConstUint(i1);
return llvm::GetElementPtrInst::Create(ptr, v.begin(), v.end(), var, bb?bb:gIR->scopebb());
}
@ -642,11 +646,8 @@ LLValue* DtoNew(Type* newtype)
// get type info
LLConstant* ti = DtoTypeInfoOf(newtype);
assert(isaPointer(ti));
// call runtime
LLSmallVector<LLValue*,1> arg;
arg.push_back(ti);
// allocate
LLValue* mem = gIR->ir->CreateCall(fn, arg.begin(), arg.end(), ".gc_mem");
// call runtime allocator
LLValue* mem = gIR->ir->CreateCall(fn, ti, ".gc_mem");
// cast
return DtoBitCast(mem, getPtrToType(DtoType(newtype)), ".gc_mem");
}
@ -707,6 +708,10 @@ void DtoAssert(Loc* loc, DValue* msg)
const char* fname = msg ? "_d_assert_msg" : "_d_assert";
llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, fname);
// param attrs
llvm::PAListPtr palist;
int idx = 1;
c = DtoConstString(loc->filename);
// msg param
@ -727,6 +732,7 @@ void DtoAssert(Loc* loc, DValue* msg)
{
args.push_back(msg->getRVal());
}
palist = palist.addAttr(idx++, llvm::ParamAttr::ByVal);
}
// file param
@ -740,7 +746,10 @@ void DtoAssert(Loc* loc, DValue* msg)
DtoStore(c->getOperand(0), ptr);
ptr = DtoGEPi(alloc, 0,1, "tmp");
DtoStore(c->getOperand(1), ptr);
args.push_back(alloc);
palist = palist.addAttr(idx++, llvm::ParamAttr::ByVal);
// line param
c = DtoConstUint(loc->linnum);
@ -748,6 +757,7 @@ void DtoAssert(Loc* loc, DValue* msg)
// call
llvm::CallInst* call = llvm::CallInst::Create(fn, args.begin(), args.end(), "", gIR->scopebb());
call->setParamAttrs(palist);
}
//////////////////////////////////////////////////////////////////////////////////////////

View file

@ -7,9 +7,12 @@
#include "attrib.h"
#include "declaration.h"
#include "gen/structs.h"
// D->LLVM type handling stuff
const LLType* DtoType(Type* t);
bool DtoIsPassedByRef(Type* type);
bool DtoIsReturnedInArg(Type* type);
// resolve typedefs to their real type.
// TODO should probably be removed in favor of DMD's Type::toBasetype
@ -54,10 +57,10 @@ llvm::Function* LLVM_DeclareMemCpy32();
llvm::Function* LLVM_DeclareMemCpy64();
// getelementptr helpers
LLValue* DtoGEP(LLValue* ptr, LLValue* i0, LLValue* i1, const std::string& var, llvm::BasicBlock* bb=NULL);
LLValue* DtoGEP(LLValue* ptr, const std::vector<unsigned>& src, const std::string& var, llvm::BasicBlock* bb=NULL);
LLValue* DtoGEPi(LLValue* ptr, unsigned i0, const std::string& var, llvm::BasicBlock* bb=NULL);
LLValue* DtoGEPi(LLValue* ptr, unsigned i0, unsigned i1, const std::string& var, llvm::BasicBlock* bb=NULL);
LLValue* DtoGEP(LLValue* ptr, LLValue* i0, LLValue* i1, const char* var, llvm::BasicBlock* bb=NULL);
LLValue* DtoGEPi(LLValue* ptr, const DStructIndexVector& src, const char* var, llvm::BasicBlock* bb=NULL);
LLValue* DtoGEPi(LLValue* ptr, unsigned i0, const char* var, llvm::BasicBlock* bb=NULL);
LLValue* DtoGEPi(LLValue* ptr, unsigned i0, unsigned i1, const char* var, llvm::BasicBlock* bb=NULL);
// dynamic memory helpers
LLValue* DtoNew(Type* newtype);

View file

@ -16,6 +16,7 @@
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetMachineRegistry.h"
#include "llvm/System/Path.h"
#include "mars.h"
#include "module.h"
@ -151,17 +152,36 @@ void Module::genobjfile()
// run optimizer
llvmdc_optimize_module(ir.module, global.params.optimizeLevel, global.params.llvmInline);
// eventually do our own path stuff, dmd's is a bit strange.
typedef llvm::sys::Path LLPath;
LLPath bcpath;
LLPath llpath;
if (global.params.fqnPaths)
{
bcpath = LLPath(md->toChars());
bcpath.appendSuffix("bc");
llpath = LLPath(md->toChars());
llpath.appendSuffix("ll");
}
else
{
bcpath = LLPath(bcfile->name->toChars());
llpath = LLPath(llfile->name->toChars());
}
// write bytecode
{
Logger::println("Writing LLVM bitcode\n");
std::ofstream bos(bcfile->name->toChars(), std::ios::binary);
std::ofstream bos(bcpath.c_str(), std::ios::binary);
llvm::WriteBitcodeToFile(ir.module, bos);
}
// disassemble ?
if (global.params.disassemble) {
Logger::println("Writing LLVM asm to: %s\n", llfile->name->toChars());
std::ofstream aos(llfile->name->toChars());
std::ofstream aos(llpath.c_str());
ir.module->print(aos);
}

View file

@ -749,7 +749,9 @@ tangotests/a.d
tangotests/aa1.d
tangotests/aa2.d
tangotests/align1.d
tangotests/arrays1.d
tangotests/b.d
tangotests/byval1.d
tangotests/c.d
tangotests/classes1.d
tangotests/constructors.d

View file

@ -47,6 +47,7 @@ private
{
void* llvm_frameaddress(uint level=0);
}
extern(C) int printf(char*, ...);
}
}
@ -161,6 +162,7 @@ extern (C) void rt_scanStaticData( scanFn scan )
}
else version( linux )
{
//printf("scanning static data from %p to %p\n", &__data_start, &_end);
scan( &__data_start, &_end );
}
else

30
tangotests/vararg4.d Normal file
View file

@ -0,0 +1,30 @@
module tangotests.vararg4;
extern(C) int printf(char*, ...);
struct S
{
int i;
}
void func(...)
{
S* sp = cast(S*)_argptr;
assert(sp.i == 42);
}
void main()
{
printf("1st:\n");
{
S s = S(42);
func(s);
}
printf("ok\n");
printf("2nd:\n");
{
func(S(42));
}
printf("ok\n");
}

View file

@ -35,7 +35,7 @@ echo
if [ -z $DMD ] ; then
echo "Testing with llvmdc. Set DMD environment variable to select compiler."
DMD="llvmdc"
DMD="llvmdc -O0"
else
echo "Using compiler given by DMD environment variable: $DMD"
fi