Skip to content

Commit c73cd86

Browse files
committed
Implement taking address of the external symbol
1 parent 95e999c commit c73cd86

File tree

5 files changed

+127
-60
lines changed

5 files changed

+127
-60
lines changed

source/tests/passing.d

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6307,7 +6307,7 @@ immutable test287 = q{--- test287.vx
63076307
};
63086308

63096309

6310-
@TestInfo()
6310+
@TestInfo(&tester288)
63116311
immutable test288 = q{--- test288.vx
63126312
// Aggregate lowering bug with constant aggregate nested inside non-constant one
63136313
struct vec3 { f32 x; f32 y; f32 z; }
@@ -6324,3 +6324,32 @@ void tester288(ref TestContext ctx) {
63246324
static struct Vertex { float pos; vec3 color; }
63256325
assert(ctx.getFunctionPtr!(Vertex, float)("putQuadAt")(56.0f) == Vertex(56.0f, vec3(1, 0, 0)));
63266326
}
6327+
6328+
6329+
/*
6330+
TODO
6331+
@TestInfo(&tester289)
6332+
immutable test289 = q{--- test289.vx
6333+
// Aggregate of float type
6334+
struct vec2 { f32 x; f32 y; }
6335+
vec2 make(f32 x, f32 y) {
6336+
return vec2(x, y);
6337+
}
6338+
};
6339+
void tester289(ref TestContext ctx) {
6340+
static struct vec2 { float x; float y; }
6341+
assert(ctx.getFunctionPtr!(vec2, float, float)("make")(56.0f, 30.0f) == vec2(56.0f, 30.0f));
6342+
}*/
6343+
6344+
6345+
@TestInfo(&tester290, [HostSymbol("noop", cast(void*)&external_noop)])
6346+
immutable test290 = q{--- test290.vx
6347+
// Taking address of the external symbol
6348+
@extern(module, "host") void noop();
6349+
void* run() {
6350+
return &noop;
6351+
}
6352+
};
6353+
void tester290(ref TestContext ctx) {
6354+
assert(ctx.getFunctionPtr!(void*)("run")() == &external_noop);
6355+
}

source/vox/be/emit_mc_amd64.d

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -907,10 +907,19 @@ struct CodeEmitter
907907
// copy address of function into register
908908
case MoveType.func_to_reg:
909909
context.assertf(dst.physRegClass == AMD64_REG_CLASS.GPR, "func_to_reg %s", dst);
910-
// HACK, TODO: 32bit version of reg is incoming, while for ptr 64bits are needed
911-
MemAddress addr = memAddrRipDisp32(0);
912-
gen.lea(dstReg, addr, cast(ArgType)IrArgSize.size64);
913-
addRefTo(src);
910+
FunctionDeclNode* func = context.getFunction(src);
911+
LinkIndex entityIndex = func.backendData.objectSymIndex;
912+
ObjectSymbol* sym = context.objSymTab.getSymbol(entityIndex);
913+
if (sym.isIndirect) {
914+
// read address from the import section
915+
MemAddress addr = memAddrRipDisp32(0);
916+
gen.mov(dstReg, addr, cast(ArgType)IrArgSize.size64);
917+
} else {
918+
// take address of the symbol
919+
MemAddress addr = memAddrRipDisp32(0);
920+
gen.lea(dstReg, addr, cast(ArgType)IrArgSize.size64);
921+
}
922+
addRefTo(entityIndex);
914923
break;
915924

916925
case MoveType.reg_to_reg:

source/vox/be/obj.d

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,12 @@ enum ObjectSymbolFlags : ushort {
9292
isIndirect = 1 << 3,
9393
/// If true, data can be printed for debug as a string
9494
isString = 1 << 4,
95+
/// If true, data can be printed for debug as an address/pointer
96+
isPointer = 1 << 5,
9597
/// If true, data can be printed for debug as a float
96-
isFloat = 1 << 5,
98+
isFloat = 1 << 6,
9799
/// Marked if transitively used from any root symbol (only used for imported symbols atm)
98-
isReferenced = 1 << 6,
100+
isReferenced = 1 << 7,
99101
}
100102

101103
enum ObjectSymbolKind : ushort {
@@ -121,7 +123,7 @@ struct ObjectSymbol
121123
Identifier id;
122124
/// Points to initializer if it is provided. (Can be null)
123125
ubyte* dataPtr;
124-
/// Offset from the start of section. Is equal to dataPtr if host symbol
126+
/// Offset from the start of section. Can be equal to dataPtr if host symbol
125127
ulong sectionOffset;
126128
/// Length in bytes. Doesn't include padding and zero termination
127129
/// Is set in setInitializer (when has initializer), or manually (when zero inited, or is external host symbol)
@@ -144,6 +146,7 @@ struct ObjectSymbol
144146
bool needsZeroTermination() { return cast(bool)(flags & ObjectSymbolFlags.needsZeroTermination); }
145147
bool isIndirect() { return cast(bool)(flags & ObjectSymbolFlags.isIndirect); }
146148
bool isString() { return cast(bool)(flags & ObjectSymbolFlags.isString); }
149+
bool isPointer() { return cast(bool)(flags & ObjectSymbolFlags.isPointer); }
147150
bool isReferenced() { return cast(bool)(flags & ObjectSymbolFlags.isReferenced); }
148151

149152
void setInitializer(ubyte[] data) {
@@ -182,11 +185,16 @@ struct ObjectModule
182185
bool isLocal() { return kind == ObjectModuleKind.isLocal; }
183186
bool isImported() { return kind == ObjectModuleKind.isImported; }
184187
bool isExternal() { return isLocal || isImported; }
188+
189+
bool isReferenced() { return cast(bool)(flags & ObjectModuleFlags.isReferenced); }
190+
bool isVerbose() { return cast(bool)(flags & ObjectModuleFlags.isVerbose); }
185191
}
186192

187193
enum ObjectModuleFlags : ushort {
188194
/// Marked if transitively used from any root symbol (only used for imported symbols atm)
189195
isReferenced = 1 << 0,
196+
/// Only printed in dump when verbose printing is enabled
197+
isVerbose = 1 << 1,
190198
}
191199

192200
@(LinkIndexKind.section)
@@ -333,12 +341,16 @@ struct ObjectSymbolTable
333341

334342
void dump(CompilationContext* c)
335343
{
336-
LinkIndex modIndex = firstModule;
337-
while (modIndex.isDefined)
344+
for (LinkIndex modIndex = firstModule; modIndex.isDefined; modIndex = getModule(modIndex).nextModule)
338345
{
339346
ObjectModule* mod = getModule(modIndex);
340347
writefln("%s %s", modIndex, c.idString(mod.id));
341348

349+
if (mod.isVerbose) {
350+
writeln(` (hidden as isVerbose)`);
351+
continue;
352+
}
353+
342354
LinkIndex symIndex = mod.firstSymbol;
343355
while (symIndex.isDefined)
344356
{
@@ -355,6 +367,16 @@ struct ObjectSymbolTable
355367
writefln(" address: 0x%08X", section.sectionAddress + sym.sectionOffset);
356368
writefln(" section: 0x%08X %s", section.sectionAddress, c.idString(section.id));
357369
writefln(" data: %s bytes", sym.length);
370+
if (sym.isString) {
371+
writefln(` as string: "%s"`, (cast(char*)(sym.dataPtr))[0..sym.length]);
372+
}
373+
if (sym.isPointer) {
374+
switch(sym.length) {
375+
case 4: writefln(` as ptr: 0x%X`, *cast(uint*)sym.dataPtr); break;
376+
case 8: writefln(` as ptr: 0x%X`, *cast(ulong*)sym.dataPtr); break;
377+
default: break;
378+
}
379+
}
358380
if (sym.dataPtr) {
359381
printHex(sym.dataPtr[0..sym.length], 16, PrintAscii.no, " ");
360382
}
@@ -363,14 +385,13 @@ struct ObjectSymbolTable
363385
while (symRefIndex.isDefined)
364386
{
365387
ObjectSymbolReference* symRef = getReference(symRefIndex);
366-
writefln(" %s -> %s: off 0x%08X extra %s %s",
388+
writefln(" %s -> %s: off 0x%08X extraOff %s %s",
367389
symRefIndex, symRef.referencedSymbol, symRef.refOffset,
368390
symRef.extraOffset, symRef.refKind);
369391
symRefIndex = symRef.nextReference;
370392
}
371393
symIndex = sym.nextSymbol;
372394
}
373-
modIndex = mod.nextModule;
374395
}
375396
}
376397

source/vox/context.d

Lines changed: 54 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -660,47 +660,67 @@ struct CompilationContext
660660
return externalModuleIndex;
661661
}
662662

663-
void addHostSymbol(LinkIndex hostModuleIndex, Identifier symId, void* symPtr)
663+
// Automatically choses to use direct referencing or to use import table to access symbol
664+
// Adds to external symbol table
665+
LinkIndex addHostSymbol(LinkIndex hostModuleIndex, Identifier symId, void* symPtr)
664666
{
665-
LinkIndex importedSymbolIndex;
666-
667+
LinkIndex symIndex;
667668
if (canReferenceFromCode(symPtr))
668-
{
669-
ObjectSymbol importedSymbol = {
670-
kind : ObjectSymbolKind.isHost,
671-
id : symId,
672-
dataPtr : cast(ubyte*)symPtr,
673-
sectionOffset : cast(ulong)symPtr,
674-
sectionIndex : builtinSections[ObjectSectionType.host],
675-
moduleIndex : hostModuleIndex,
676-
};
677-
importedSymbolIndex = objSymTab.addSymbol(importedSymbol);
678-
}
669+
symIndex = addHostSymbolDirect(hostModuleIndex, symId, symPtr);
679670
else
680-
{
681-
ulong sectionOffset = importBuffer.length;
682-
ulong ptr = cast(ulong)symPtr;
683-
importBuffer.put(*cast(ubyte[8]*)&ptr);
684-
685-
ObjectSymbol importedSymbol = {
686-
kind : ObjectSymbolKind.isHost,
687-
flags : ObjectSymbolFlags.isIndirect,
688-
id : symId,
689-
sectionOffset : sectionOffset,
690-
sectionIndex : builtinSections[ObjectSectionType.imports],
691-
moduleIndex : hostModuleIndex,
692-
};
693-
importedSymbolIndex = objSymTab.addSymbol(importedSymbol);
694-
}
695-
Identifier modId = objSymTab.getModule(hostModuleIndex).id;
696-
externalSymbols.put(arrayArena, ExternalSymbolId(modId, symId), importedSymbolIndex);
671+
symIndex = addHostSymbolIndirect(hostModuleIndex, symId, symPtr);
672+
673+
registerExternalSymbol(hostModuleIndex, symId, symIndex);
674+
675+
return symIndex;
676+
}
677+
678+
// Force host symbol to be accessed directly
679+
private LinkIndex addHostSymbolDirect(LinkIndex hostModuleIndex, Identifier symId, void* symPtr)
680+
{
681+
ObjectSymbol sym = {
682+
kind : ObjectSymbolKind.isHost,
683+
id : symId,
684+
dataPtr : cast(ubyte*)symPtr,
685+
sectionOffset : cast(ulong)symPtr,
686+
sectionIndex : builtinSections[ObjectSectionType.host],
687+
moduleIndex : hostModuleIndex,
688+
};
689+
return objSymTab.addSymbol(sym);
690+
}
691+
692+
// Force host symbol to be accessed through import table
693+
private LinkIndex addHostSymbolIndirect(LinkIndex hostModuleIndex, Identifier symId, void* symPtr)
694+
{
695+
ulong sectionOffset = importBuffer.length;
696+
ubyte* dataPtr = importBuffer.nextPtr;
697+
size_t ptr = cast(size_t)symPtr;
698+
importBuffer.put(*cast(ubyte[size_t.sizeof]*)&ptr);
699+
700+
ObjectSymbol sym = {
701+
kind : ObjectSymbolKind.isHost,
702+
flags : ObjectSymbolFlags.isIndirect | ObjectSymbolFlags.isPointer,
703+
id : symId,
704+
dataPtr : dataPtr,
705+
length : size_t.sizeof,
706+
sectionOffset : sectionOffset,
707+
sectionIndex : builtinSections[ObjectSectionType.imports],
708+
moduleIndex : hostModuleIndex,
709+
};
710+
return objSymTab.addSymbol(sym);
711+
}
712+
713+
private void registerExternalSymbol(LinkIndex moduleIndex, Identifier symId, LinkIndex symIndex)
714+
{
715+
Identifier modId = objSymTab.getModule(moduleIndex).id;
716+
externalSymbols.put(arrayArena, ExternalSymbolId(modId, symId), symIndex);
697717
}
698718

699719
LinkIndex addDllModuleSymbol(LinkIndex dllModuleIndex, Identifier symId)
700720
{
701721
ObjectSymbol importedSymbol = {
702722
kind : ObjectSymbolKind.isImported,
703-
flags : ObjectSymbolFlags.isIndirect,
723+
flags : ObjectSymbolFlags.isIndirect | ObjectSymbolFlags.isPointer,
704724
id : symId,
705725
alignmentPower : 3, // pointer size
706726
sectionIndex : builtinSections[ObjectSectionType.imports],
@@ -1242,6 +1262,7 @@ void createBuiltinFunctions(CompilationContext* c)
12421262
{
12431263
ObjectModule builtinModule = {
12441264
kind : ObjectModuleKind.isHost,
1265+
flags : ObjectModuleFlags.isVerbose,
12451266
id : c.idMap.getOrReg(c, ":builtin")
12461267
};
12471268
c.builtinModuleIndex = c.objSymTab.addModule(builtinModule);
@@ -1273,19 +1294,7 @@ void createBuiltinFunctions(CompilationContext* c)
12731294
funcNode.state = AstNodeState.type_check_done;
12741295
funcNode.flags |= FuncDeclFlags.isBuiltin;
12751296

1276-
ulong sectionOffset = c.importBuffer.length;
1277-
ulong ptr = cast(ulong)&builtin_function_stub;
1278-
c.importBuffer.put(*cast(ubyte[8]*)&ptr);
1279-
1280-
ObjectSymbol sym = {
1281-
kind : ObjectSymbolKind.isHost,
1282-
flags : ObjectSymbolFlags.isIndirect,
1283-
id : id,
1284-
sectionOffset : sectionOffset,
1285-
sectionIndex : c.builtinSections[ObjectSectionType.imports],
1286-
moduleIndex : c.builtinModuleIndex,
1287-
};
1288-
funcNode.backendData.objectSymIndex = c.objSymTab.addSymbol(sym);
1297+
funcNode.backendData.objectSymIndex = c.addHostSymbolIndirect(c.builtinModuleIndex, id, &builtin_function_stub);
12891298

12901299
c.assertf(func == reqIndex,
12911300
"Result AstIndex of builtin node %s (%s) is not equal to required (%s). Creation order must match CommonAstNodes order",

source/vox/fe/ast/decl/func.d

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ struct FunctionDeclNode {
5050
bool isCtfeOnly(CompilationContext* c) {
5151
return signature.get!FunctionSignatureNode(c).isCtfeOnly;
5252
}
53+
/// External functions have no body
54+
bool isExternal() { return block_stmt.isUndefined; }
5355

5456
this(TokenIndex loc, AstIndex _module, ScopeIndex parameterScope, AstIndex signature, Identifier id)
5557
{
@@ -69,9 +71,6 @@ struct FunctionDeclNode {
6971
AstIndex index = get_ast_index(&this, c);
7072
return IrIndex(index.storageIndex, IrValueKind.func);
7173
}
72-
73-
/// External functions have no body
74-
bool isExternal() { return block_stmt.isUndefined; }
7574
}
7675

7776
void print_func(FunctionDeclNode* node, ref AstPrintState state)

0 commit comments

Comments
 (0)