Skip to content

Commit 0817716

Browse files
committed
C-backend: don't mangle type names, fix field names, fix C unions
1 parent 9d20e33 commit 0817716

File tree

10 files changed

+89
-66
lines changed

10 files changed

+89
-66
lines changed

src/ast/mangle.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,7 @@ std::string cx::mangleFunctionDecl(const FunctionDecl& functionDecl) {
112112
} else {
113113
stream << cxPrefix;
114114
stream << 'N';
115-
116-
mangleIdentifier(stream, functionDecl.getModule()->getName());
115+
mangleIdentifier(stream, functionDecl.module.name);
117116

118117
if (auto* typeDecl = functionDecl.getTypeDecl()) {
119118
mangleIdentifier(stream, typeDecl->getName());

src/ast/module.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ struct SymbolTable {
126126

127127
/// Container for the AST of a whole module, comprised of one or more SourceFiles.
128128
struct Module {
129-
Module(llvm::StringRef name) : name(name) {}
129+
Module(std::string&& name) : name(std::move(name)) {}
130130
void addSourceFile(SourceFile&& file) { sourceFiles.emplace_back(std::move(file)); }
131131
llvm::ArrayRef<SourceFile> getSourceFiles() const { return sourceFiles; }
132132
llvm::MutableArrayRef<SourceFile> getSourceFiles() { return sourceFiles; }

src/backend/c-backend.cpp

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ void CGenerator::codegenExtract(const ExtractInst* inst) {
169169
auto name = "_extract" + std::to_string(valueSuffixCounter++);
170170
stream << "__auto_type " << name << " = ";
171171
codegenInst(inst->aggregate);
172-
stream << "._" << inst->index;
172+
stream << "." << inst->name;
173173
stream << ";\n";
174174
emittedValues.insert({inst, std::move(name)});
175175
}
@@ -311,7 +311,7 @@ void CGenerator::codegenConstGEP(const ConstGEPInst* inst) {
311311
auto name = "_const_get_element_ptr" + std::to_string(valueSuffixCounter++);
312312
stream << "__auto_type " << name << " = &";
313313
codegenInst(inst->pointer);
314-
stream << "->_" << inst->index << ";\n";
314+
stream << "->" << inst->name << ";\n";
315315
emittedValues.insert({inst, std::move(name)});
316316
}
317317

@@ -389,7 +389,7 @@ const std::string& CGenerator::getBlockLabel(const BasicBlock* block) {
389389
return it->second;
390390
} else {
391391
auto name = block->name;
392-
std::replace(name.begin(), name.end(), '.', '_');
392+
llvm::replace(name, '.', '_');
393393
llvm::raw_string_ostream os(name);
394394
os << valueSuffixCounter++;
395395
return emittedValues.insert({block, std::move(os.str())}).first->second;
@@ -614,30 +614,29 @@ void CGenerator::codegenTypeDefinition(llvm::raw_string_ostream& stream, IRType*
614614
case IRTypeKind::IRStructType: {
615615
// Generate struct definition if this is the first time we encounter this type.
616616
auto* irStruct = llvm::cast<IRStructType>(type);
617-
if (!alreadyEmittedTypes.contains(type)) {
617+
if (!irStruct->isImportedFromC && !alreadyEmittedTypes.contains(type)) {
618618
alreadyEmittedTypes.insert(type);
619619

620620
// Generate type dependencies first.
621-
for (auto* elementType : irStruct->elementTypes) {
622-
codegenTypeDefinition(stream, elementType);
621+
for (auto& field : irStruct->fields) {
622+
codegenTypeDefinition(stream, field.type);
623623
}
624624

625625
stream << "\nstruct " << irStruct->mangledName << " {\n";
626-
int memberIndex = 0;
627-
for (auto* elementType : irStruct->elementTypes) {
626+
for (auto& field : irStruct->fields) {
628627
stream.indent(4);
629-
codegenType(stream, elementType, true);
630-
stream << " _" << (memberIndex++); // TODO: add names to IRStruct fields for clearer C code gen?
631-
codegenTypeSuffix(stream, elementType, true);
628+
codegenType(stream, field.type, true);
629+
stream << " " << field.name;
630+
codegenTypeSuffix(stream, field.type, true);
632631
stream << ";\n";
633632
}
634633
stream << "};\n";
635634
}
636635
break;
637636
}
638637
case IRTypeKind::IRUnionType:
639-
for (auto* elementType : llvm::cast<IRUnionType>(type)->elementTypes) {
640-
codegenTypeDefinition(stream, elementType);
638+
for (auto& field : llvm::cast<IRUnionType>(type)->fields) {
639+
codegenTypeDefinition(stream, field.type);
641640
}
642641
break;
643642
}

src/backend/ir.cpp

Lines changed: 48 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
#include "ir.h"
22
#pragma warning(push, 0)
3+
#include <llvm/ADT/SmallString.h>
34
#include <llvm/ADT/StringSet.h>
45
#include <llvm/ADT/StringSwitch.h>
56
#pragma warning(pop)
67
#include "../ast/decl.h"
78
#include "../ast/mangle.h"
9+
#include "../ast/module.h"
810

911
using namespace cx;
1012

@@ -34,21 +36,39 @@ IRType* cx::getIRType(Type astType) {
3436

3537
if (enumDecl->hasAssociatedValues()) {
3638
auto unionType = new IRUnionType{IRTypeKind::IRUnionType, {}, ""};
37-
irType = new IRStructType{IRTypeKind::IRStructType, {tagType, unionType}, astType.getQualifiedTypeName(), '_' + mangleType(astType), false};
39+
irType = new IRStructType{IRTypeKind::IRStructType,
40+
{IRField{tagType, "tag"}, IRField{unionType, "union"}},
41+
astType.getQualifiedTypeName(),
42+
'_' + mangleType(astType),
43+
false,
44+
false};
3845
irTypes.emplace(astType.getBase(), irType);
39-
auto associatedTypes = map(enumDecl->cases, [](const EnumCase& c) { return getIRType(c.associatedType); });
40-
unionType->elementTypes = std::move(associatedTypes);
46+
auto associatedTypes = map(enumDecl->cases, [](const EnumCase& c) { return IRField{getIRType(c.associatedType), c.name}; });
47+
unionType->fields = std::move(associatedTypes);
4148
return irType;
4249
} else {
4350
irType = tagType;
4451
}
45-
} else if (astType.getDecl()) {
46-
auto structType =
47-
new IRStructType{IRTypeKind::IRStructType, {}, astType.getQualifiedTypeName(), '_' + mangleType(astType), astType.getDecl()->packed};
48-
irTypes.emplace(astType.getBase(), structType);
49-
auto elementTypes = map(astType.getDecl()->fields, [](const FieldDecl& f) { return getIRType(f.type); });
50-
structType->elementTypes = std::move(elementTypes);
51-
return structType;
52+
} else if (auto decl = astType.getDecl()) {
53+
if (decl->isUnion()) {
54+
auto unionType = new IRUnionType{IRTypeKind::IRUnionType, {}, astType.getQualifiedTypeName()};
55+
irTypes.emplace(astType.getBase(), unionType);
56+
// Fields are set late to handle recursive types.
57+
unionType->fields = map(decl->fields, [](const FieldDecl& f) { return IRField{getIRType(f.type), f.name}; });
58+
return unionType;
59+
} else {
60+
bool isImportedFromC = decl->module.name.ends_with("_h");
61+
auto structType = new IRStructType{IRTypeKind::IRStructType,
62+
{},
63+
astType.getQualifiedTypeName(),
64+
isImportedFromC ? astType.getName().str() : ('_' + mangleType(astType)),
65+
decl->packed,
66+
isImportedFromC};
67+
irTypes.emplace(astType.getBase(), structType);
68+
// Fields are set late to handle recursive types.
69+
structType->fields = map(decl->fields, [](const FieldDecl& f) { return IRField{getIRType(f.type), f.name}; });
70+
return structType;
71+
}
5272
} else {
5373
llvm_unreachable(StringBuilder() << "unknown type '" << astType << "'");
5474
}
@@ -65,8 +85,8 @@ IRType* cx::getIRType(Type astType) {
6585
break;
6686
}
6787
case TypeKind::TupleType: {
68-
auto elementTypes = map(astType.getTupleElements(), [](const TupleElement& e) { return getIRType(e.type); });
69-
irType = new IRStructType{IRTypeKind::IRStructType, std::move(elementTypes), std::string(), std::string(), false};
88+
auto fields = map(astType.getTupleElements(), [](const TupleElement& e) { return IRField{getIRType(e.type), e.name}; });
89+
irType = new IRStructType{IRTypeKind::IRStructType, std::move(fields), std::string(), std::string(), false, false};
7090
break;
7191
}
7292
case TypeKind::FunctionType: {
@@ -114,7 +134,7 @@ IRType* Value::getType() const {
114134
return llvm::cast<InsertInst>(this)->aggregate->getType();
115135
case ValueKind::ExtractInst: {
116136
auto extract = llvm::cast<ExtractInst>(this);
117-
return extract->aggregate->getType()->getElements()[extract->index];
137+
return extract->aggregate->getType()->getFields()[extract->index].type;
118138
}
119139
case ValueKind::CallInst: {
120140
auto functionType = llvm::cast<CallInst>(this)->function->getType();
@@ -171,8 +191,8 @@ IRType* Value::getType() const {
171191
auto baseType = gep->pointer->getType()->getPointee();
172192
switch (baseType->kind) {
173193
case IRTypeKind::IRStructType:
174-
ASSERT(gep->index < baseType->getElements().size());
175-
return baseType->getElements()[gep->index]->getPointerTo();
194+
ASSERT(gep->index < baseType->getFields().size());
195+
return baseType->getFields()[gep->index].type->getPointerTo();
176196
case IRTypeKind::IRArrayType:
177197
ASSERT(gep->index < baseType->getArraySize());
178198
return baseType->getElementType()->getPointerTo();
@@ -605,9 +625,9 @@ IRType* IRType::getPointee() {
605625
return llvm::cast<IRPointerType>(this)->pointee;
606626
}
607627

608-
llvm::ArrayRef<IRType*> IRType::getElements() {
609-
if (isUnion()) return llvm::cast<IRUnionType>(this)->elementTypes;
610-
return llvm::cast<IRStructType>(this)->elementTypes;
628+
llvm::ArrayRef<IRField> IRType::getFields() {
629+
if (isUnion()) return llvm::cast<IRUnionType>(this)->fields;
630+
return llvm::cast<IRStructType>(this)->fields;
611631
}
612632

613633
llvm::StringRef IRType::getName() {
@@ -659,10 +679,10 @@ llvm::raw_ostream& cx::operator<<(llvm::raw_ostream& stream, IRType* type) {
659679
if (type->getName() != "") {
660680
return stream << type->getName();
661681
} else {
662-
stream << "{ ";
663-
for (auto& element : type->getElements()) {
664-
stream << element;
665-
if (&element != &type->getElements().back()) stream << ", ";
682+
stream << "struct { ";
683+
for (auto& field : type->getFields()) {
684+
stream << field.type;
685+
if (&field != &type->getFields().back()) stream << ", ";
666686
}
667687
return stream << " }";
668688
}
@@ -672,13 +692,9 @@ llvm::raw_ostream& cx::operator<<(llvm::raw_ostream& stream, IRType* type) {
672692
return stream << type->getName();
673693
} else {
674694
stream << "union { ";
675-
for (auto& element : type->getElements()) {
676-
if (element) { // TODO: Element type should exist for all associated values
677-
stream << element;
678-
} else {
679-
stream << "void";
680-
}
681-
if (&element != &type->getElements().back()) stream << ", ";
695+
for (auto& field : type->getFields()) {
696+
stream << field.type;
697+
if (&field != &type->getFields().back()) stream << ", ";
682698
}
683699
return stream << " }";
684700
}
@@ -714,9 +730,9 @@ bool IRType::equals(IRType* other) {
714730
if (!other->isStruct()) return false;
715731
if (getName() != other->getName()) return false;
716732
if (getName().empty()) {
717-
if (getElements().size() != other->getElements().size()) return false;
718-
for (size_t i = 0; i < getElements().size(); ++i) {
719-
if (!getElements()[i]->equals(other->getElements()[i])) return false;
733+
if (getFields().size() != other->getFields().size()) return false;
734+
for (size_t i = 0; i < getFields().size(); ++i) {
735+
if (!getFields()[i].type->equals(other->getFields()[i].type)) return false;
720736
}
721737
}
722738
return true;

src/backend/ir.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ struct Function;
2424
struct BasicBlock;
2525
struct Instruction;
2626
struct Parameter;
27+
struct IRField;
2728

2829
enum class IRTypeKind {
2930
IRBasicType,
@@ -52,7 +53,7 @@ struct IRType {
5253
bool isVoid();
5354
bool isNever();
5455
IRType* getPointee();
55-
llvm::ArrayRef<IRType*> getElements();
56+
llvm::ArrayRef<IRField> getFields();
5657
llvm::StringRef getName();
5758
IRType* getReturnType();
5859
llvm::ArrayRef<IRType*> getParamTypes();
@@ -90,17 +91,24 @@ struct IRArrayType : IRType {
9091
static bool classof(const IRType* t) { return t->kind == IRTypeKind::IRArrayType; }
9192
};
9293

94+
struct IRField {
95+
IRType* type;
96+
std::string name;
97+
};
98+
9399
struct IRStructType : IRType {
94-
std::vector<IRType*> elementTypes;
100+
std::vector<IRField> fields;
95101
std::string name;
96102
std::string mangledName;
97103
bool packed;
104+
bool isImportedFromC;
98105

99106
static bool classof(const IRType* t) { return t->kind == IRTypeKind::IRStructType; }
100107
};
101108

109+
// TODO: combine IRUnionType to IRStructType?
102110
struct IRUnionType : IRType {
103-
std::vector<IRType*> elementTypes;
111+
std::vector<IRField> fields;
104112
std::string name;
105113

106114
static bool classof(const IRType* t) { return t->kind == IRTypeKind::IRUnionType; }

src/backend/irgen.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#include <vector>
44
#pragma warning(push, 0)
55
#include <llvm/ADT/DenseMap.h>
6-
#include <llvm/ADT/StringSet.h>
6+
#include <llvm/ADT/Twine.h>
77
#pragma warning(pop)
88
#include "../ast/decl.h"
99
#include "../ast/expr.h"
@@ -172,7 +172,7 @@ struct IRGenerator {
172172
if (pointer->getType()->getPointee()->isArrayType()) {
173173
ASSERT(index < pointer->getType()->getPointee()->getArraySize());
174174
} else {
175-
ASSERT(index < pointer->getType()->getPointee()->getElements().size());
175+
ASSERT(index < pointer->getType()->getPointee()->getFields().size());
176176
}
177177
return insertBlock->add(new ConstGEPInst{ValueKind::ConstGEPInst, pointer, index, expr, name.str()});
178178
}

src/backend/llvm.cpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,18 @@ llvm::Type* LLVMGenerator::getBuiltinType(llvm::StringRef name) {
3838

3939
llvm::Type* LLVMGenerator::getStructType(IRStructType* type) {
4040
if (type->name.empty()) {
41-
auto elementTypes = map(type->elementTypes, [&](IRType* elementType) { return getLLVMType(elementType); });
41+
auto fields = map(type->fields, [&](const IRField& field) { return getLLVMType(field.type); });
4242
// TODO: can these be cached to `structs` as well?
43-
return llvm::StructType::get(ctx, std::move(elementTypes), type->packed);
43+
return llvm::StructType::get(ctx, std::move(fields), type->packed);
4444
}
4545

4646
auto it = structs.find(type);
4747
if (it != structs.end()) return NOTNULL(it->second);
4848

4949
auto llvmStruct = llvm::StructType::create(ctx, type->getName());
5050
structs.try_emplace(type, llvmStruct);
51-
auto elementTypes = map(type->elementTypes, [&](IRType* elementType) { return getLLVMType(elementType); });
52-
llvmStruct->setBody(std::move(elementTypes), type->packed);
51+
auto fields = map(type->fields, [&](const IRField& field) { return getLLVMType(field.type); });
52+
llvmStruct->setBody(std::move(fields), type->packed);
5353
return llvmStruct;
5454
}
5555

@@ -95,9 +95,8 @@ llvm::Type* LLVMGenerator::getLLVMType(IRType* type, bool* isSret) {
9595
structs.try_emplace(unionType, structType);
9696

9797
unsigned maxSize = 0;
98-
for (auto* field : unionType->getElements()) {
99-
if (!field) continue;
100-
auto size = module->getDataLayout().getTypeAllocSize(getLLVMType(field));
98+
for (auto& field : unionType->getFields()) {
99+
auto size = module->getDataLayout().getTypeAllocSize(getLLVMType(field.type));
101100
if (size > maxSize) maxSize = size;
102101
}
103102

src/sema/c-import.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,9 @@ bool cx::importCHeader(SourceFile& importer, ImportDecl& importDecl, Typechecker
464464
if (headerPath.empty()) headerPath = headerName;
465465
importDecl.importedHeaderPath = headerPath;
466466

467-
auto module = new Module(headerName);
467+
std::string headerModuleName = headerName.str();
468+
llvm::replace(headerModuleName, '.', '_');
469+
auto module = new Module(std::move(headerModuleName));
468470
module->addSourceFile(SourceFile(headerPath, module));
469471

470472
auto cToCxConverter = new CToCxConverter(*module, typechecker, targetInfo, ci.getSourceManager());
@@ -486,6 +488,6 @@ bool cx::importCHeader(SourceFile& importer, ImportDecl& importDecl, Typechecker
486488
}
487489

488490
importer.addImportedModule(module);
489-
Module::getAllImportedModulesMap()[module->getName()] = module;
491+
Module::getAllImportedModulesMap()[headerName] = module;
490492
return true;
491493
}

src/sema/typecheck-expr.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -877,11 +877,11 @@ static const Match* findMatchByPredicate(llvm::ArrayRef<Match> matches, const Ca
877877
}
878878

879879
static bool isStdlibDecl(const Match& match) {
880-
return match.decl->getModule() && match.decl->getModule()->getName() == "std";
880+
return match.decl->getModule() && match.decl->getModule()->name == "std";
881881
}
882882

883883
static bool isCHeaderDecl(const Match& match) {
884-
return match.decl->getModule() && match.decl->getModule()->getName().ends_with(".h");
884+
return match.decl->getModule() && match.decl->getModule()->name.ends_with("_h");
885885
}
886886

887887
static const Match* resolveAmbiguousOverload(llvm::ArrayRef<Match> matches, const CallExpr& call) {

src/sema/typecheck.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ llvm::ErrorOr<const Module&> Typechecker::importModule(SourceFile* importer, con
6666
return *it->second;
6767
}
6868

69-
auto module = new Module(moduleName);
69+
auto module = new Module(moduleName.str());
7070
std::error_code error;
7171

7272
if (manifest) {
@@ -247,7 +247,7 @@ static Decl* findDeclInModules(llvm::StringRef name, Location location, llvm::Ar
247247
return decls[0];
248248
} else if (decls.empty()) {
249249
return nullptr;
250-
} else if (llvm::all_of(decls, [](Decl* decl) { return decl->getModule() && decl->getModule()->getName().ends_with(".h"); })) {
250+
} else if (llvm::all_of(decls, [](Decl* decl) { return decl->getModule() && decl->getModule()->name.ends_with("_h"); })) {
251251
// For duplicate definitions in C headers, return the last definition.
252252
// TODO: This should only work for declarations of the same thing.
253253
return decls.back(); // For duplicate definitions in C headers, return the last definition.

0 commit comments

Comments
 (0)