forked from OSchip/llvm-project
[WebAssembly] Add support for data sections in the assembler.
Summary: This is quite minimal so far, introduce them with .section, fill them with .int8 or .asciz, end with .size Reviewers: dschuff, sbc100, aheejin Subscribers: jgravelle-google, sunfish, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D58660 llvm-svn: 355321
This commit is contained in:
parent
de11105d2e
commit
f3feb6adb9
|
@ -130,11 +130,27 @@ public:
|
||||||
if (expect(AsmToken::Comma, ",") || expect(AsmToken::At, "@") ||
|
if (expect(AsmToken::Comma, ",") || expect(AsmToken::At, "@") ||
|
||||||
expect(AsmToken::EndOfStatement, "eol"))
|
expect(AsmToken::EndOfStatement, "eol"))
|
||||||
return true;
|
return true;
|
||||||
// This is done automatically by the assembler for text sections currently,
|
struct SectionType {
|
||||||
// so we don't need to emit that here. This is what it would do (and may
|
const char *Name;
|
||||||
// be needed later for other section types):
|
SectionKind Kind;
|
||||||
// auto WS = getContext().getWasmSection(Name, SectionKind::getText());
|
};
|
||||||
// getStreamer().SwitchSection(WS);
|
static SectionType SectionTypes[] = {
|
||||||
|
{ ".text", SectionKind::getText() },
|
||||||
|
{ ".rodata", SectionKind::getReadOnly() },
|
||||||
|
{ ".data", SectionKind::getData() },
|
||||||
|
// TODO: add more types.
|
||||||
|
};
|
||||||
|
for (size_t I = 0; I < sizeof(SectionTypes) / sizeof(SectionType); I++) {
|
||||||
|
if (Name.startswith(SectionTypes[I].Name)) {
|
||||||
|
auto WS = getContext().getWasmSection(Name, SectionTypes[I].Kind);
|
||||||
|
getStreamer().SwitchSection(WS);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Not found, just ignore this section.
|
||||||
|
// For code in a text section WebAssemblyAsmParser automatically adds
|
||||||
|
// one section per function, so they're optional to be specified with
|
||||||
|
// this directive.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,9 +169,8 @@ public:
|
||||||
if (expect(AsmToken::EndOfStatement, "eol"))
|
if (expect(AsmToken::EndOfStatement, "eol"))
|
||||||
return true;
|
return true;
|
||||||
// This is done automatically by the assembler for functions currently,
|
// This is done automatically by the assembler for functions currently,
|
||||||
// so we don't need to emit that here. This is what it would do:
|
// so this is only currently needed for data sections:
|
||||||
(void)Sym;
|
getStreamer().emitELFSize(Sym, Expr);
|
||||||
// getStreamer().emitELFSize(Sym, Expr);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1348,7 +1348,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
|
||||||
LLVM_DEBUG(dbgs() << " -> function index: " << Index << "\n");
|
LLVM_DEBUG(dbgs() << " -> function index: " << Index << "\n");
|
||||||
|
|
||||||
} else if (WS.isData()) {
|
} else if (WS.isData()) {
|
||||||
if (WS.isTemporary() && !WS.getSize())
|
if (!isInSymtab(WS))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!WS.isDefined()) {
|
if (!WS.isDefined()) {
|
||||||
|
|
|
@ -172,6 +172,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
|
||||||
FunctionLocals,
|
FunctionLocals,
|
||||||
Instructions,
|
Instructions,
|
||||||
EndFunction,
|
EndFunction,
|
||||||
|
DataSection,
|
||||||
} CurrentState = FileStart;
|
} CurrentState = FileStart;
|
||||||
|
|
||||||
// For ensuring blocks are properly nested.
|
// For ensuring blocks are properly nested.
|
||||||
|
@ -552,6 +553,17 @@ public:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CheckDataSection() {
|
||||||
|
if (CurrentState != DataSection) {
|
||||||
|
auto WS = cast<MCSectionWasm>(getStreamer().getCurrentSection().first);
|
||||||
|
if (WS && WS->getKind().isText())
|
||||||
|
return error("data directive must occur in a data segment: ",
|
||||||
|
Lexer.getTok());
|
||||||
|
}
|
||||||
|
CurrentState = DataSection;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// This function processes wasm-specific directives streamed to
|
// This function processes wasm-specific directives streamed to
|
||||||
// WebAssemblyTargetStreamer, all others go to the generic parser
|
// WebAssemblyTargetStreamer, all others go to the generic parser
|
||||||
// (see WasmAsmParser).
|
// (see WasmAsmParser).
|
||||||
|
@ -650,6 +662,25 @@ public:
|
||||||
return expect(AsmToken::EndOfStatement, "EOL");
|
return expect(AsmToken::EndOfStatement, "EOL");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (DirectiveID.getString() == ".int8") {
|
||||||
|
if (CheckDataSection()) return true;
|
||||||
|
int64_t V;
|
||||||
|
if (Parser.parseAbsoluteExpression(V))
|
||||||
|
return error("Cannot parse int8 constant: ", Lexer.getTok());
|
||||||
|
// TODO: error if value doesn't fit?
|
||||||
|
Out.EmitIntValue(static_cast<uint64_t>(V), 1);
|
||||||
|
return expect(AsmToken::EndOfStatement, "EOL");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DirectiveID.getString() == ".asciz") {
|
||||||
|
if (CheckDataSection()) return true;
|
||||||
|
std::string S;
|
||||||
|
if (Parser.parseEscapedString(S))
|
||||||
|
return error("Cannot parse string constant: ", Lexer.getTok());
|
||||||
|
Out.EmitBytes(StringRef(S.c_str(), S.length() + 1));
|
||||||
|
return expect(AsmToken::EndOfStatement, "EOL");
|
||||||
|
}
|
||||||
|
|
||||||
return true; // We didn't process this directive.
|
return true; // We didn't process this directive.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -717,9 +748,10 @@ public:
|
||||||
void onEndOfFunction() {
|
void onEndOfFunction() {
|
||||||
// Automatically output a .size directive, so it becomes optional for the
|
// Automatically output a .size directive, so it becomes optional for the
|
||||||
// user.
|
// user.
|
||||||
|
if (!LastFunctionLabel) return;
|
||||||
auto TempSym = getContext().createLinkerPrivateTempSymbol();
|
auto TempSym = getContext().createLinkerPrivateTempSymbol();
|
||||||
getStreamer().EmitLabel(TempSym);
|
getStreamer().EmitLabel(TempSym);
|
||||||
auto Start = MCSymbolRefExpr::create(LastLabel, getContext());
|
auto Start = MCSymbolRefExpr::create(LastFunctionLabel, getContext());
|
||||||
auto End = MCSymbolRefExpr::create(TempSym, getContext());
|
auto End = MCSymbolRefExpr::create(TempSym, getContext());
|
||||||
auto Expr =
|
auto Expr =
|
||||||
MCBinaryExpr::create(MCBinaryExpr::Sub, End, Start, getContext());
|
MCBinaryExpr::create(MCBinaryExpr::Sub, End, Start, getContext());
|
||||||
|
|
|
@ -77,12 +77,19 @@ test0:
|
||||||
.LBB0_4:
|
.LBB0_4:
|
||||||
end_block
|
end_block
|
||||||
end_try
|
end_try
|
||||||
i32.const 0
|
i32.const .L.str
|
||||||
throw 0
|
throw 0
|
||||||
.LBB0_5:
|
.LBB0_5:
|
||||||
#i32.trunc_sat_f32_s
|
#i32.trunc_sat_f32_s
|
||||||
global.get __stack_pointer
|
global.get __stack_pointer
|
||||||
end_function
|
end_function
|
||||||
|
|
||||||
|
.section .rodata..L.str,"",@
|
||||||
|
.L.str:
|
||||||
|
.int8 'H'
|
||||||
|
.asciz "ello, World!"
|
||||||
|
.size .L.str, 14
|
||||||
|
|
||||||
.globaltype __stack_pointer, i32
|
.globaltype __stack_pointer, i32
|
||||||
|
|
||||||
# CHECK: .text
|
# CHECK: .text
|
||||||
|
@ -154,10 +161,15 @@ test0:
|
||||||
# CHECK-NEXT: .LBB0_4:
|
# CHECK-NEXT: .LBB0_4:
|
||||||
# CHECK-NEXT: end_block
|
# CHECK-NEXT: end_block
|
||||||
# CHECK-NEXT: end_try
|
# CHECK-NEXT: end_try
|
||||||
# CHECK-NEXT: i32.const 0
|
# CHECK-NEXT: i32.const .L.str
|
||||||
# CHECK-NEXT: throw 0
|
# CHECK-NEXT: throw 0
|
||||||
# CHECK-NEXT: .LBB0_5:
|
# CHECK-NEXT: .LBB0_5:
|
||||||
# CHECK-NEXT: global.get __stack_pointer
|
# CHECK-NEXT: global.get __stack_pointer
|
||||||
# CHECK-NEXT: end_function
|
# CHECK-NEXT: end_function
|
||||||
|
|
||||||
|
# CHECK: .section .rodata..L.str,"",@
|
||||||
|
# CHECK-NEXT:.L.str:
|
||||||
|
# CHECK-NEXT: .int8 72
|
||||||
|
# CHECK-NEXT: .asciz "ello, World!"
|
||||||
|
|
||||||
# CHECK: .globaltype __stack_pointer, i32
|
# CHECK: .globaltype __stack_pointer, i32
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+unimplemented-simd128,+nontrapping-fptoint,+exception-handling < %s | FileCheck %s
|
||||||
|
# Check that it converts to .o without errors:
|
||||||
|
# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj -mattr=+unimplemented-simd128,+nontrapping-fptoint,+exception-handling < %s | obj2yaml | FileCheck -check-prefix=BIN %s
|
||||||
|
|
||||||
|
# Minimal test for data sections.
|
||||||
|
|
||||||
|
test0:
|
||||||
|
.functype test0 () -> (i32)
|
||||||
|
i32.const .L.str
|
||||||
|
.Ltestlabel:
|
||||||
|
end_function
|
||||||
|
|
||||||
|
.section .rodata..L.str,"",@
|
||||||
|
.L.str:
|
||||||
|
.int8 100
|
||||||
|
.size .L.str, 1
|
||||||
|
|
||||||
|
|
||||||
|
# CHECK: .text
|
||||||
|
# CHECK-LABEL: test0:
|
||||||
|
# CHECK-NEXT: .functype test0 () -> (i32)
|
||||||
|
# CHECK-NEXT: i32.const .L.str
|
||||||
|
# CHECK-NEXT: .Ltestlabel:
|
||||||
|
# CHECK-NEXT: end_function
|
||||||
|
|
||||||
|
# CHECK: .section .rodata..L.str,"",@
|
||||||
|
# CHECK-NEXT:.L.str:
|
||||||
|
# CHECK-NEXT: .int8 100
|
||||||
|
|
||||||
|
|
||||||
|
# BIN: --- !WASM
|
||||||
|
# BIN-NEXT: FileHeader:
|
||||||
|
# BIN-NEXT: Version: 0x00000001
|
||||||
|
# BIN-NEXT: Sections:
|
||||||
|
# BIN-NEXT: - Type: TYPE
|
||||||
|
# BIN-NEXT: Signatures:
|
||||||
|
# BIN-NEXT: - Index: 0
|
||||||
|
# BIN-NEXT: ReturnType: I32
|
||||||
|
# BIN-NEXT: ParamTypes: []
|
||||||
|
# BIN-NEXT: - Type: IMPORT
|
||||||
|
# BIN-NEXT: Imports:
|
||||||
|
# BIN-NEXT: - Module: env
|
||||||
|
# BIN-NEXT: Field: __linear_memory
|
||||||
|
# BIN-NEXT: Kind: MEMORY
|
||||||
|
# BIN-NEXT: Memory:
|
||||||
|
# BIN-NEXT: Initial: 0x00000001
|
||||||
|
# BIN-NEXT: - Module: env
|
||||||
|
# BIN-NEXT: Field: __indirect_function_table
|
||||||
|
# BIN-NEXT: Kind: TABLE
|
||||||
|
# BIN-NEXT: Table:
|
||||||
|
# BIN-NEXT: ElemType: FUNCREF
|
||||||
|
# BIN-NEXT: Limits:
|
||||||
|
# BIN-NEXT: Initial: 0x00000000
|
||||||
|
# BIN-NEXT: - Type: FUNCTION
|
||||||
|
# BIN-NEXT: FunctionTypes: [ 0 ]
|
||||||
|
# BIN-NEXT: - Type: CODE
|
||||||
|
# BIN-NEXT: Relocations:
|
||||||
|
# BIN-NEXT: - Type: R_WASM_MEMORY_ADDR_SLEB
|
||||||
|
# BIN-NEXT: Index: 1
|
||||||
|
# BIN-NEXT: Offset: 0x00000004
|
||||||
|
# BIN-NEXT: Functions:
|
||||||
|
# BIN-NEXT: - Index: 0
|
||||||
|
# BIN-NEXT: Locals: []
|
||||||
|
# BIN-NEXT: Body: 4180808080000B
|
||||||
|
# BIN-NEXT: - Type: DATA
|
||||||
|
# BIN-NEXT: Segments:
|
||||||
|
# BIN-NEXT: - SectionOffset: 6
|
||||||
|
# BIN-NEXT: InitFlags: 0
|
||||||
|
# BIN-NEXT: Offset:
|
||||||
|
# BIN-NEXT: Opcode: I32_CONST
|
||||||
|
# BIN-NEXT: Value: 0
|
||||||
|
# BIN-NEXT: Content: '64'
|
||||||
|
# BIN-NEXT: - Type: CUSTOM
|
||||||
|
# BIN-NEXT: Name: linking
|
||||||
|
# BIN-NEXT: Version: 2
|
||||||
|
# BIN-NEXT: SymbolTable:
|
||||||
|
# BIN-NEXT: - Index: 0
|
||||||
|
# BIN-NEXT: Kind: FUNCTION
|
||||||
|
# BIN-NEXT: Name: test0
|
||||||
|
# BIN-NEXT: Flags: [ BINDING_LOCAL ]
|
||||||
|
# BIN-NEXT: Function: 0
|
||||||
|
# BIN-NEXT: - Index: 1
|
||||||
|
# BIN-NEXT: Kind: DATA
|
||||||
|
# BIN-NEXT: Name: .L.str
|
||||||
|
# BIN-NEXT: Flags: [ BINDING_LOCAL ]
|
||||||
|
# BIN-NEXT: Segment: 0
|
||||||
|
# BIN-NEXT: Size: 1
|
||||||
|
# BIN-NEXT: SegmentInfo:
|
||||||
|
# BIN-NEXT: - Index: 0
|
||||||
|
# BIN-NEXT: Name: .rodata..L.str
|
||||||
|
# BIN-NEXT: Alignment: 0
|
||||||
|
# BIN-NEXT: Flags: [ ]
|
||||||
|
# BIN-NEXT: ...
|
||||||
|
|
Loading…
Reference in New Issue