Skip to content

Commit 9504ab3

Browse files
committed
[WebAssembly] Second phase of implemented extended const proposal
This change continues to lay the ground work for supporting extended const expressions in the linker. The included test covers object file reading and writing and the YAML representation. Differential Revision: https://reviews.llvm.org/D121349
1 parent 8361c5d commit 9504ab3

File tree

15 files changed

+271
-130
lines changed

15 files changed

+271
-130
lines changed

lld/wasm/InputElement.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,13 @@ class InputElement {
4444

4545
inline WasmInitExpr intConst(uint64_t value, bool is64) {
4646
WasmInitExpr ie;
47+
ie.Extended = false;
4748
if (is64) {
48-
ie.Opcode = llvm::wasm::WASM_OPCODE_I64_CONST;
49-
ie.Value.Int64 = static_cast<int64_t>(value);
49+
ie.Inst.Opcode = llvm::wasm::WASM_OPCODE_I64_CONST;
50+
ie.Inst.Value.Int64 = static_cast<int64_t>(value);
5051
} else {
51-
ie.Opcode = llvm::wasm::WASM_OPCODE_I32_CONST;
52-
ie.Value.Int32 = static_cast<int32_t>(value);
52+
ie.Inst.Opcode = llvm::wasm::WASM_OPCODE_I32_CONST;
53+
ie.Inst.Value.Int32 = static_cast<int32_t>(value);
5354
}
5455
return ie;
5556
}

lld/wasm/InputFiles.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -412,10 +412,12 @@ void ObjFile::parse(bool ignoreComdats) {
412412
tableEntries.resize(totalFunctions);
413413
for (const WasmElemSegment &seg : wasmObj->elements()) {
414414
int64_t offset;
415-
if (seg.Offset.Opcode == WASM_OPCODE_I32_CONST)
416-
offset = seg.Offset.Value.Int32;
417-
else if (seg.Offset.Opcode == WASM_OPCODE_I64_CONST)
418-
offset = seg.Offset.Value.Int64;
415+
if (seg.Offset.Extended)
416+
fatal(toString(this) + ": extended init exprs not supported");
417+
else if (seg.Offset.Inst.Opcode == WASM_OPCODE_I32_CONST)
418+
offset = seg.Offset.Inst.Value.Int32;
419+
else if (seg.Offset.Inst.Opcode == WASM_OPCODE_I64_CONST)
420+
offset = seg.Offset.Inst.Value.Int64;
419421
else
420422
fatal(toString(this) + ": invalid table elements");
421423
for (size_t index = 0; index < seg.Functions.size(); index++) {

lld/wasm/OutputSections.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,9 +159,10 @@ void DataSection::finalizeContents() {
159159
writeUleb128(os, 0, "memory index");
160160
if ((segment->initFlags & WASM_DATA_SEGMENT_IS_PASSIVE) == 0) {
161161
WasmInitExpr initExpr;
162+
initExpr.Extended = false;
162163
if (config->isPic) {
163-
initExpr.Opcode = WASM_OPCODE_GLOBAL_GET;
164-
initExpr.Value.Global = WasmSym::memoryBase->getGlobalIndex();
164+
initExpr.Inst.Opcode = WASM_OPCODE_GLOBAL_GET;
165+
initExpr.Inst.Value.Global = WasmSym::memoryBase->getGlobalIndex();
165166
} else {
166167
initExpr = intConst(segment->startVA, config->is64.getValueOr(false));
167168
}

lld/wasm/SyntheticSections.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -542,15 +542,16 @@ void ElemSection::writeBody() {
542542
writeUleb128(os, tableNumber, "table number");
543543

544544
WasmInitExpr initExpr;
545+
initExpr.Extended = false;
545546
if (config->isPic) {
546-
initExpr.Opcode = WASM_OPCODE_GLOBAL_GET;
547-
initExpr.Value.Global =
547+
initExpr.Inst.Opcode = WASM_OPCODE_GLOBAL_GET;
548+
initExpr.Inst.Value.Global =
548549
(config->is64.getValueOr(false) ? WasmSym::tableBase32
549550
: WasmSym::tableBase)
550551
->getGlobalIndex();
551552
} else {
552-
initExpr.Opcode = WASM_OPCODE_I32_CONST;
553-
initExpr.Value.Int32 = config->tableBase;
553+
initExpr.Inst.Opcode = WASM_OPCODE_I32_CONST;
554+
initExpr.Inst.Value.Int32 = config->tableBase;
554555
}
555556
writeInitExpr(os, initExpr);
556557

lld/wasm/WriterUtils.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,11 @@ void writeMemArg(raw_ostream &os, uint32_t alignment, uint64_t offset) {
159159
}
160160

161161
void writeInitExpr(raw_ostream &os, const WasmInitExpr &initExpr) {
162+
assert(!initExpr.Extended);
163+
writeInitExprMVP(os, initExpr.Inst);
164+
}
165+
166+
void writeInitExprMVP(raw_ostream &os, const WasmInitExprMVP &initExpr) {
162167
writeU8(os, initExpr.Opcode, "opcode");
163168
switch (initExpr.Opcode) {
164169
case WASM_OPCODE_I32_CONST:

lld/wasm/WriterUtils.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ void writeMemArg(raw_ostream &os, uint32_t alignment, uint64_t offset);
5151

5252
void writeInitExpr(raw_ostream &os, const llvm::wasm::WasmInitExpr &initExpr);
5353

54+
void writeInitExprMVP(raw_ostream &os,
55+
const llvm::wasm::WasmInitExprMVP &initExpr);
56+
5457
void writeLimits(raw_ostream &os, const llvm::wasm::WasmLimits &limits);
5558

5659
void writeGlobalType(raw_ostream &os, const llvm::wasm::WasmGlobalType &type);

llvm/include/llvm/BinaryFormat/Wasm.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ struct WasmTable {
9191
StringRef SymbolName; // from the "linking" section
9292
};
9393

94-
struct WasmInitExpr {
94+
struct WasmInitExprMVP {
9595
uint8_t Opcode;
9696
union {
9797
int32_t Int32;
@@ -102,6 +102,13 @@ struct WasmInitExpr {
102102
} Value;
103103
};
104104

105+
struct WasmInitExpr {
106+
uint8_t Extended; // Set to non-zero if extended const is used (i.e. more than
107+
// one instruction)
108+
WasmInitExprMVP Inst;
109+
ArrayRef<uint8_t> Body;
110+
};
111+
105112
struct WasmGlobalType {
106113
uint8_t Type;
107114
bool Mutable;
@@ -285,7 +292,11 @@ enum : unsigned {
285292
WASM_OPCODE_F32_CONST = 0x43,
286293
WASM_OPCODE_F64_CONST = 0x44,
287294
WASM_OPCODE_I32_ADD = 0x6a,
295+
WASM_OPCODE_I32_SUB = 0x6b,
296+
WASM_OPCODE_I32_MUL = 0x6c,
288297
WASM_OPCODE_I64_ADD = 0x7c,
298+
WASM_OPCODE_I64_SUB = 0x7d,
299+
WASM_OPCODE_I64_MUL = 0x7e,
289300
WASM_OPCODE_REF_NULL = 0xd0,
290301
};
291302

llvm/include/llvm/ObjectYAML/WasmYAML.h

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,31 +62,41 @@ struct Export {
6262
uint32_t Index;
6363
};
6464

65+
struct InitExpr {
66+
InitExpr() {}
67+
bool Extended;
68+
union {
69+
wasm::WasmInitExprMVP Inst;
70+
yaml::BinaryRef Body;
71+
};
72+
};
73+
6574
struct ElemSegment {
6675
uint32_t Flags;
6776
uint32_t TableNumber;
6877
ValueType ElemKind;
69-
wasm::WasmInitExpr Offset;
78+
InitExpr Offset;
7079
std::vector<uint32_t> Functions;
7180
};
7281

7382
struct Global {
7483
uint32_t Index;
7584
ValueType Type;
7685
bool Mutable;
77-
wasm::WasmInitExpr InitExpr;
86+
InitExpr InitExpr;
7887
};
7988

8089
struct Import {
90+
Import() {}
8191
StringRef Module;
8292
StringRef Field;
8393
ExportKind Kind;
8494
union {
8595
uint32_t SigIndex;
86-
Global GlobalImport;
8796
Table TableImport;
8897
Limits Memory;
8998
uint32_t TagIndex;
99+
Global GlobalImport;
90100
};
91101
};
92102

@@ -114,7 +124,7 @@ struct DataSegment {
114124
uint32_t SectionOffset;
115125
uint32_t InitFlags;
116126
uint32_t MemoryIndex;
117-
wasm::WasmInitExpr Offset;
127+
InitExpr Offset;
118128
yaml::BinaryRef Content;
119129
};
120130

@@ -526,8 +536,8 @@ template <> struct MappingTraits<WasmYAML::LocalDecl> {
526536
static void mapping(IO &IO, WasmYAML::LocalDecl &LocalDecl);
527537
};
528538

529-
template <> struct MappingTraits<wasm::WasmInitExpr> {
530-
static void mapping(IO &IO, wasm::WasmInitExpr &Expr);
539+
template <> struct MappingTraits<WasmYAML::InitExpr> {
540+
static void mapping(IO &IO, WasmYAML::InitExpr &Expr);
531541
};
532542

533543
template <> struct MappingTraits<WasmYAML::DataSegment> {

llvm/lib/MC/WasmObjectWriter.cpp

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -931,25 +931,29 @@ void WasmObjectWriter::writeGlobalSection(ArrayRef<wasm::WasmGlobal> Globals) {
931931
for (const wasm::WasmGlobal &Global : Globals) {
932932
encodeULEB128(Global.Type.Type, W->OS);
933933
W->OS << char(Global.Type.Mutable);
934-
W->OS << char(Global.InitExpr.Opcode);
935-
switch (Global.Type.Type) {
936-
case wasm::WASM_TYPE_I32:
937-
encodeSLEB128(0, W->OS);
938-
break;
939-
case wasm::WASM_TYPE_I64:
940-
encodeSLEB128(0, W->OS);
941-
break;
942-
case wasm::WASM_TYPE_F32:
943-
writeI32(0);
944-
break;
945-
case wasm::WASM_TYPE_F64:
946-
writeI64(0);
947-
break;
948-
case wasm::WASM_TYPE_EXTERNREF:
949-
writeValueType(wasm::ValType::EXTERNREF);
950-
break;
951-
default:
952-
llvm_unreachable("unexpected type");
934+
if (Global.InitExpr.Extended) {
935+
llvm_unreachable("extected init expressions not supported");
936+
} else {
937+
W->OS << char(Global.InitExpr.Inst.Opcode);
938+
switch (Global.Type.Type) {
939+
case wasm::WASM_TYPE_I32:
940+
encodeSLEB128(0, W->OS);
941+
break;
942+
case wasm::WASM_TYPE_I64:
943+
encodeSLEB128(0, W->OS);
944+
break;
945+
case wasm::WASM_TYPE_F32:
946+
writeI32(0);
947+
break;
948+
case wasm::WASM_TYPE_F64:
949+
writeI64(0);
950+
break;
951+
case wasm::WASM_TYPE_EXTERNREF:
952+
writeValueType(wasm::ValType::EXTERNREF);
953+
break;
954+
default:
955+
llvm_unreachable("unexpected type");
956+
}
953957
}
954958
W->OS << char(wasm::WASM_OPCODE_END);
955959
}
@@ -1658,21 +1662,22 @@ uint64_t WasmObjectWriter::writeOneObject(MCAssembler &Asm,
16581662
wasm::WasmGlobal Global;
16591663
Global.Type = WS.getGlobalType();
16601664
Global.Index = NumGlobalImports + Globals.size();
1665+
Global.InitExpr.Extended = false;
16611666
switch (Global.Type.Type) {
16621667
case wasm::WASM_TYPE_I32:
1663-
Global.InitExpr.Opcode = wasm::WASM_OPCODE_I32_CONST;
1668+
Global.InitExpr.Inst.Opcode = wasm::WASM_OPCODE_I32_CONST;
16641669
break;
16651670
case wasm::WASM_TYPE_I64:
1666-
Global.InitExpr.Opcode = wasm::WASM_OPCODE_I64_CONST;
1671+
Global.InitExpr.Inst.Opcode = wasm::WASM_OPCODE_I64_CONST;
16671672
break;
16681673
case wasm::WASM_TYPE_F32:
1669-
Global.InitExpr.Opcode = wasm::WASM_OPCODE_F32_CONST;
1674+
Global.InitExpr.Inst.Opcode = wasm::WASM_OPCODE_F32_CONST;
16701675
break;
16711676
case wasm::WASM_TYPE_F64:
1672-
Global.InitExpr.Opcode = wasm::WASM_OPCODE_F64_CONST;
1677+
Global.InitExpr.Inst.Opcode = wasm::WASM_OPCODE_F64_CONST;
16731678
break;
16741679
case wasm::WASM_TYPE_EXTERNREF:
1675-
Global.InitExpr.Opcode = wasm::WASM_OPCODE_REF_NULL;
1680+
Global.InitExpr.Inst.Opcode = wasm::WASM_OPCODE_REF_NULL;
16761681
break;
16771682
default:
16781683
llvm_unreachable("unexpected type");

llvm/lib/Object/WasmObjectFile.cpp

Lines changed: 56 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -164,23 +164,25 @@ static uint8_t readOpcode(WasmObjectFile::ReadContext &Ctx) {
164164

165165
static Error readInitExpr(wasm::WasmInitExpr &Expr,
166166
WasmObjectFile::ReadContext &Ctx) {
167-
Expr.Opcode = readOpcode(Ctx);
167+
auto Start = Ctx.Ptr;
168168

169-
switch (Expr.Opcode) {
169+
Expr.Extended = false;
170+
Expr.Inst.Opcode = readOpcode(Ctx);
171+
switch (Expr.Inst.Opcode) {
170172
case wasm::WASM_OPCODE_I32_CONST:
171-
Expr.Value.Int32 = readVarint32(Ctx);
173+
Expr.Inst.Value.Int32 = readVarint32(Ctx);
172174
break;
173175
case wasm::WASM_OPCODE_I64_CONST:
174-
Expr.Value.Int64 = readVarint64(Ctx);
176+
Expr.Inst.Value.Int64 = readVarint64(Ctx);
175177
break;
176178
case wasm::WASM_OPCODE_F32_CONST:
177-
Expr.Value.Float32 = readFloat32(Ctx);
179+
Expr.Inst.Value.Float32 = readFloat32(Ctx);
178180
break;
179181
case wasm::WASM_OPCODE_F64_CONST:
180-
Expr.Value.Float64 = readFloat64(Ctx);
182+
Expr.Inst.Value.Float64 = readFloat64(Ctx);
181183
break;
182184
case wasm::WASM_OPCODE_GLOBAL_GET:
183-
Expr.Value.Global = readULEB128(Ctx);
185+
Expr.Inst.Value.Global = readULEB128(Ctx);
184186
break;
185187
case wasm::WASM_OPCODE_REF_NULL: {
186188
wasm::ValType Ty = static_cast<wasm::ValType>(readULEB128(Ctx));
@@ -191,15 +193,46 @@ static Error readInitExpr(wasm::WasmInitExpr &Expr,
191193
break;
192194
}
193195
default:
194-
return make_error<GenericBinaryError>("invalid opcode in init_expr",
195-
object_error::parse_failed);
196+
Expr.Extended = true;
196197
}
197198

198-
uint8_t EndOpcode = readOpcode(Ctx);
199-
if (EndOpcode != wasm::WASM_OPCODE_END) {
200-
return make_error<GenericBinaryError>("invalid init_expr",
201-
object_error::parse_failed);
199+
if (!Expr.Extended) {
200+
uint8_t EndOpcode = readOpcode(Ctx);
201+
if (EndOpcode != wasm::WASM_OPCODE_END)
202+
Expr.Extended = true;
203+
}
204+
205+
if (Expr.Extended) {
206+
Ctx.Ptr = Start;
207+
while (1) {
208+
uint8_t Opcode = readOpcode(Ctx);
209+
switch (Opcode) {
210+
case wasm::WASM_OPCODE_I32_CONST:
211+
case wasm::WASM_OPCODE_GLOBAL_GET:
212+
case wasm::WASM_OPCODE_REF_NULL:
213+
case wasm::WASM_OPCODE_I64_CONST:
214+
case wasm::WASM_OPCODE_F32_CONST:
215+
case wasm::WASM_OPCODE_F64_CONST:
216+
readULEB128(Ctx);
217+
break;
218+
case wasm::WASM_OPCODE_I32_ADD:
219+
case wasm::WASM_OPCODE_I32_SUB:
220+
case wasm::WASM_OPCODE_I32_MUL:
221+
case wasm::WASM_OPCODE_I64_ADD:
222+
case wasm::WASM_OPCODE_I64_SUB:
223+
case wasm::WASM_OPCODE_I64_MUL:
224+
break;
225+
case wasm::WASM_OPCODE_END:
226+
Expr.Body = ArrayRef<uint8_t>(Start, Ctx.Ptr - Start);
227+
return Error::success();
228+
default:
229+
return make_error<GenericBinaryError>(
230+
Twine("invalid opcode in init_expr: ") + Twine(unsigned(Opcode)),
231+
object_error::parse_failed);
232+
}
233+
}
202234
}
235+
203236
return Error::success();
204237
}
205238

@@ -1441,8 +1474,8 @@ Error WasmObjectFile::parseElemSection(ReadContext &Ctx) {
14411474
object_error::parse_failed);
14421475

14431476
if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_PASSIVE) {
1444-
Segment.Offset.Opcode = wasm::WASM_OPCODE_I32_CONST;
1445-
Segment.Offset.Value.Int32 = 0;
1477+
Segment.Offset.Inst.Opcode = wasm::WASM_OPCODE_I32_CONST;
1478+
Segment.Offset.Inst.Value.Int32 = 0;
14461479
} else {
14471480
if (Error Err = readInitExpr(Segment.Offset, Ctx))
14481481
return Err;
@@ -1501,8 +1534,8 @@ Error WasmObjectFile::parseDataSection(ReadContext &Ctx) {
15011534
if (Error Err = readInitExpr(Segment.Data.Offset, Ctx))
15021535
return Err;
15031536
} else {
1504-
Segment.Data.Offset.Opcode = wasm::WASM_OPCODE_I32_CONST;
1505-
Segment.Data.Offset.Value.Int32 = 0;
1537+
Segment.Data.Offset.Inst.Opcode = wasm::WASM_OPCODE_I32_CONST;
1538+
Segment.Data.Offset.Inst.Value.Int32 = 0;
15061539
}
15071540
uint32_t Size = readVaruint32(Ctx);
15081541
if (Size > (size_t)(Ctx.End - Ctx.Ptr))
@@ -1600,10 +1633,12 @@ uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol &Sym) const {
16001633
// offset within the segment.
16011634
uint32_t SegmentIndex = Sym.Info.DataRef.Segment;
16021635
const wasm::WasmDataSegment &Segment = DataSegments[SegmentIndex].Data;
1603-
if (Segment.Offset.Opcode == wasm::WASM_OPCODE_I32_CONST) {
1604-
return Segment.Offset.Value.Int32 + Sym.Info.DataRef.Offset;
1605-
} else if (Segment.Offset.Opcode == wasm::WASM_OPCODE_I64_CONST) {
1606-
return Segment.Offset.Value.Int64 + Sym.Info.DataRef.Offset;
1636+
if (Segment.Offset.Extended) {
1637+
llvm_unreachable("extended init exprs not supported");
1638+
} else if (Segment.Offset.Inst.Opcode == wasm::WASM_OPCODE_I32_CONST) {
1639+
return Segment.Offset.Inst.Value.Int32 + Sym.Info.DataRef.Offset;
1640+
} else if (Segment.Offset.Inst.Opcode == wasm::WASM_OPCODE_I64_CONST) {
1641+
return Segment.Offset.Inst.Value.Int64 + Sym.Info.DataRef.Offset;
16071642
} else {
16081643
llvm_unreachable("unknown init expr opcode");
16091644
}

0 commit comments

Comments
 (0)