1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
|
//===-- structs.cpp -------------------------------------------------------===//
//
// LDC – the LLVM D compiler
//
// This file is distributed under the BSD-style LDC license. See the LICENSE
// file for details.
//
//===----------------------------------------------------------------------===//
#include "gen/structs.h"
#include "dmd/aggregate.h"
#include "dmd/declaration.h"
#include "dmd/errors.h"
#include "dmd/init.h"
#include "dmd/module.h"
#include "dmd/mtype.h"
#include "gen/arrays.h"
#include "gen/dvalue.h"
#include "gen/functions.h"
#include "gen/irstate.h"
#include "gen/llvm.h"
#include "gen/llvmhelpers.h"
#include "gen/logger.h"
#include "gen/tollvm.h"
#include "ir/iraggr.h"
#include "ir/irdsymbol.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/ManagedStatic.h"
#include <algorithm>
////////////////////////////////////////////////////////////////////////////////
void DtoResolveStruct(StructDeclaration *sd) { DtoResolveStruct(sd, sd->loc); }
void DtoResolveStruct(StructDeclaration *sd, const Loc &callerLoc) {
// Make sure to resolve each struct type exactly once.
if (sd->ir->isResolved()) {
return;
}
sd->ir->setResolved();
IF_LOG Logger::println("Resolving struct type: %s (%s)", sd->toChars(),
sd->loc.toChars());
LOG_SCOPE;
// make sure type exists
DtoType(sd->type);
// if it's a forward declaration, all bets are off. The type should be enough
if (sd->sizeok != Sizeok::done) {
error(callerLoc, "struct `%s.%s` unknown size", sd->getModule()->toChars(),
sd->toChars());
fatal();
}
// create the IrAggr
getIrAggr(sd, true);
// Set up our field metadata.
for (auto vd : sd->fields) {
IF_LOG {
if (isIrFieldCreated(vd)) {
Logger::println("struct field already exists");
}
}
getIrField(vd, true);
}
}
////////////////////////////////////////////////////////////////////////////////
//////////////////////////// D STRUCT UTILITIES
///////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
LLValue *DtoStructEquals(EXP op, DValue *lhs, DValue *rhs) {
Type *t = lhs->type->toBasetype();
assert(t->ty == TY::Tstruct);
// set predicate
llvm::ICmpInst::Predicate cmpop;
if (op == EXP::equal || op == EXP::identity) {
cmpop = llvm::ICmpInst::ICMP_EQ;
} else {
cmpop = llvm::ICmpInst::ICMP_NE;
}
// empty struct? EQ always true, NE always false
if (static_cast<TypeStruct *>(t)->sym->fields.length == 0) {
return DtoConstBool(cmpop == llvm::ICmpInst::ICMP_EQ);
}
// call memcmp
size_t sz = getTypeAllocSize(DtoType(t));
LLValue *val = DtoMemCmp(DtoLVal(lhs), DtoLVal(rhs), DtoConstSize_t(sz));
return gIR->ir->CreateICmp(cmpop, val,
LLConstantInt::get(val->getType(), 0, false));
}
////////////////////////////////////////////////////////////////////////////////
/// Return the type returned by DtoUnpaddedStruct called on a value of the
/// specified type.
/// Union types will get expanded into a struct, with a type for each member.
LLType *DtoUnpaddedStructType(Type *dty) {
assert(dty->ty == TY::Tstruct);
typedef llvm::DenseMap<Type *, llvm::StructType *> CacheT;
static llvm::ManagedStatic<CacheT> cache;
auto it = cache->find(dty);
if (it != cache->end()) {
return it->second;
}
TypeStruct *sty = static_cast<TypeStruct *>(dty);
VarDeclarations &fields = sty->sym->fields;
std::vector<LLType *> types;
types.reserve(fields.length);
for (unsigned i = 0; i < fields.length; i++) {
LLType *fty;
if (fields[i]->type->ty == TY::Tstruct) {
// Nested structs are the only members that can contain padding
fty = DtoUnpaddedStructType(fields[i]->type);
} else {
fty = DtoType(fields[i]->type);
}
types.push_back(fty);
}
LLStructType *Ty = LLStructType::get(gIR->context(), types);
cache->insert(std::make_pair(dty, Ty));
return Ty;
}
/// Return the struct value represented by v without the padding fields.
/// Unions will be expanded, with a value for each member.
/// Note: v must be a pointer to a struct, but the return value will be a
/// first-class struct value.
LLValue *DtoUnpaddedStruct(Type *dty, LLValue *v) {
assert(dty->ty == TY::Tstruct);
TypeStruct *sty = static_cast<TypeStruct *>(dty);
VarDeclarations &fields = sty->sym->fields;
LLValue *newval = llvm::UndefValue::get(DtoUnpaddedStructType(dty));
for (unsigned i = 0; i < fields.length; i++) {
LLValue *fieldptr = DtoIndexAggregate(v, sty->sym, fields[i]);
LLValue *fieldval;
if (fields[i]->type->ty == TY::Tstruct) {
// Nested structs are the only members that can contain padding
fieldval = DtoUnpaddedStruct(fields[i]->type, fieldptr);
} else {
fieldval = DtoLoad(fieldptr);
}
newval = DtoInsertValue(newval, fieldval, i);
}
return newval;
}
/// Undo the transformation performed by DtoUnpaddedStruct, writing to lval.
void DtoPaddedStruct(Type *dty, LLValue *v, LLValue *lval) {
assert(dty->ty == TY::Tstruct);
TypeStruct *sty = static_cast<TypeStruct *>(dty);
VarDeclarations &fields = sty->sym->fields;
for (unsigned i = 0; i < fields.length; i++) {
LLValue *fieldptr = DtoIndexAggregate(lval, sty->sym, fields[i]);
LLValue *fieldval = DtoExtractValue(v, i);
if (fields[i]->type->ty == TY::Tstruct) {
// Nested structs are the only members that can contain padding
DtoPaddedStruct(fields[i]->type, fieldval, fieldptr);
} else {
DtoStoreZextI8(fieldval, fieldptr);
}
}
}
|