Skip to content

Commit c8d0d8a

Browse files
committed
[ms] [llvm-ml] Add support for ALIGN, EVEN, and ORG directives
Match ML.EXE's behavior for ALIGN, EVEN, and ORG directives both at file level and in STRUCTs. We currently reject negative offsets passed to ORG inside STRUCTs (in ML.EXE and ML64.EXE, they wrap around as for an unsigned 32-bit integer). Also, if a STRUCT is declared using an ORG directive, no value of that type can be defined. Reviewed By: thakis Differential Revision: https://reviews.llvm.org/D92507
1 parent 4cf7c6c commit c8d0d8a

File tree

3 files changed

+273
-60
lines changed

3 files changed

+273
-60
lines changed

llvm/lib/MC/MCParser/MasmParser.cpp

Lines changed: 136 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,11 @@ struct FieldInfo;
128128
struct StructInfo {
129129
StringRef Name;
130130
bool IsUnion = false;
131+
bool Initializable = true;
131132
unsigned Alignment = 0;
132-
unsigned Size = 0;
133133
unsigned AlignmentSize = 0;
134+
unsigned NextOffset = 0;
135+
unsigned Size = 0;
134136
std::vector<FieldInfo> Fields;
135137
StringMap<size_t> FieldsByName;
136138

@@ -322,7 +324,7 @@ struct StructInitializer {
322324

323325
struct FieldInfo {
324326
// Offset of the field within the containing STRUCT.
325-
size_t Offset = 0;
327+
unsigned Offset = 0;
326328

327329
// Total size of the field (= LengthOf * Type).
328330
unsigned SizeOf = 0;
@@ -344,11 +346,10 @@ FieldInfo &StructInfo::addField(StringRef FieldName, FieldType FT,
344346
FieldsByName[FieldName.lower()] = Fields.size();
345347
Fields.emplace_back(FT);
346348
FieldInfo &Field = Fields.back();
347-
if (IsUnion) {
348-
Field.Offset = 0;
349-
} else {
350-
Size = llvm::alignTo(Size, std::min(Alignment, FieldAlignmentSize));
351-
Field.Offset = Size;
349+
Field.Offset =
350+
llvm::alignTo(NextOffset, std::min(Alignment, FieldAlignmentSize));
351+
if (!IsUnion) {
352+
NextOffset = std::max(NextOffset, Field.Offset);
352353
}
353354
AlignmentSize = std::max(AlignmentSize, FieldAlignmentSize);
354355
return Field;
@@ -669,6 +670,7 @@ class MasmParser : public MCAsmParser {
669670
DK_REAL8,
670671
DK_REAL10,
671672
DK_ALIGN,
673+
DK_EVEN,
672674
DK_ORG,
673675
DK_ENDR,
674676
DK_EXTERN,
@@ -871,8 +873,11 @@ class MasmParser : public MCAsmParser {
871873
bool parseDirectiveEquate(StringRef IDVal, StringRef Name,
872874
DirectiveKind DirKind, SMLoc NameLoc);
873875

874-
bool parseDirectiveOrg(); // ".org"
876+
bool parseDirectiveOrg(); // "org"
877+
878+
bool emitAlignTo(int64_t Alignment);
875879
bool parseDirectiveAlign(); // "align"
880+
bool parseDirectiveEven(); // "even"
876881

877882
// ".file", ".line", ".loc", ".stabs"
878883
bool parseDirectiveFile(SMLoc DirectiveLoc);
@@ -2332,6 +2337,8 @@ bool MasmParser::parseStatement(ParseStatementInfo &Info,
23322337
return parseDirectiveNestedEnds();
23332338
case DK_ALIGN:
23342339
return parseDirectiveAlign();
2340+
case DK_EVEN:
2341+
return parseDirectiveEven();
23352342
case DK_ORG:
23362343
return parseDirectiveOrg();
23372344
case DK_EXTERN:
@@ -3663,10 +3670,11 @@ bool MasmParser::addIntegralField(StringRef Name, unsigned Size) {
36633670

36643671
Field.SizeOf = Field.Type * IntInfo.Values.size();
36653672
Field.LengthOf = IntInfo.Values.size();
3666-
if (Struct.IsUnion)
3667-
Struct.Size = std::max(Struct.Size, Field.SizeOf);
3668-
else
3669-
Struct.Size += Field.SizeOf;
3673+
const unsigned FieldEnd = Field.Offset + Field.SizeOf;
3674+
if (!Struct.IsUnion) {
3675+
Struct.NextOffset = FieldEnd;
3676+
}
3677+
Struct.Size = std::max(Struct.Size, FieldEnd);
36703678
return false;
36713679
}
36723680

@@ -3869,10 +3877,12 @@ bool MasmParser::addRealField(StringRef Name, const fltSemantics &Semantics,
38693877
Field.Type = RealInfo.AsIntValues.back().getBitWidth() / 8;
38703878
Field.LengthOf = RealInfo.AsIntValues.size();
38713879
Field.SizeOf = Field.Type * Field.LengthOf;
3872-
if (Struct.IsUnion)
3873-
Struct.Size = std::max(Struct.Size, Field.SizeOf);
3874-
else
3875-
Struct.Size += Field.SizeOf;
3880+
3881+
const unsigned FieldEnd = Field.Offset + Field.SizeOf;
3882+
if (!Struct.IsUnion) {
3883+
Struct.NextOffset = FieldEnd;
3884+
}
3885+
Struct.Size = std::max(Struct.Size, FieldEnd);
38763886
return false;
38773887
}
38783888

@@ -4281,14 +4291,16 @@ bool MasmParser::emitFieldInitializer(const FieldInfo &Field,
42814291
const StructFieldInfo &Contents,
42824292
const StructFieldInfo &Initializer) {
42834293
for (const auto &Init : Initializer.Initializers) {
4284-
emitStructInitializer(Contents.Structure, Init);
4294+
if (emitStructInitializer(Contents.Structure, Init))
4295+
return true;
42854296
}
42864297
// Default-initialize all remaining values.
42874298
for (auto It =
42884299
Contents.Initializers.begin() + Initializer.Initializers.size();
42894300
It != Contents.Initializers.end(); ++It) {
42904301
const auto &Init = *It;
4291-
emitStructInitializer(Contents.Structure, Init);
4302+
if (emitStructInitializer(Contents.Structure, Init))
4303+
return true;
42924304
}
42934305
return false;
42944306
}
@@ -4311,6 +4323,10 @@ bool MasmParser::emitFieldInitializer(const FieldInfo &Field,
43114323

43124324
bool MasmParser::emitStructInitializer(const StructInfo &Structure,
43134325
const StructInitializer &Initializer) {
4326+
if (!Structure.Initializable)
4327+
return Error(getLexer().getLoc(),
4328+
"cannot initialize a value of type '" + Structure.Name +
4329+
"'; 'org' was used in the type's declaration");
43144330
size_t Index = 0, Offset = 0;
43154331
for (const auto &Init : Initializer.FieldInitializers) {
43164332
const auto &Field = Structure.Fields[Index++];
@@ -4367,10 +4383,12 @@ bool MasmParser::addStructField(StringRef Name, const StructInfo &Structure) {
43674383

43684384
Field.LengthOf = StructInfo.Initializers.size();
43694385
Field.SizeOf = Field.Type * Field.LengthOf;
4370-
if (OwningStruct.IsUnion)
4371-
OwningStruct.Size = std::max(OwningStruct.Size, Field.SizeOf);
4372-
else
4373-
OwningStruct.Size += Field.SizeOf;
4386+
4387+
const unsigned FieldEnd = Field.Offset + Field.SizeOf;
4388+
if (!OwningStruct.IsUnion) {
4389+
OwningStruct.NextOffset = FieldEnd;
4390+
}
4391+
OwningStruct.Size = std::max(OwningStruct.Size, FieldEnd);
43744392

43754393
return false;
43764394
}
@@ -4520,6 +4538,8 @@ bool MasmParser::parseDirectiveNestedEnds() {
45204538

45214539
StructInfo &ParentStruct = StructInProgress.back();
45224540
if (Structure.Name.empty()) {
4541+
// Anonymous substructures' fields are addressed as if they belong to the
4542+
// parent structure - so we transfer them to the parent here.
45234543
const size_t OldFields = ParentStruct.Fields.size();
45244544
ParentStruct.Fields.insert(
45254545
ParentStruct.Fields.end(),
@@ -4529,17 +4549,28 @@ bool MasmParser::parseDirectiveNestedEnds() {
45294549
ParentStruct.FieldsByName[FieldByName.getKey()] =
45304550
FieldByName.getValue() + OldFields;
45314551
}
4532-
if (!ParentStruct.IsUnion) {
4552+
4553+
unsigned FirstFieldOffset = 0;
4554+
if (!Structure.Fields.empty() && !ParentStruct.IsUnion) {
4555+
FirstFieldOffset = llvm::alignTo(
4556+
ParentStruct.NextOffset,
4557+
std::min(ParentStruct.Alignment, Structure.AlignmentSize));
4558+
}
4559+
4560+
if (ParentStruct.IsUnion) {
4561+
ParentStruct.Size = std::max(ParentStruct.Size, Structure.Size);
4562+
} else {
45334563
for (auto FieldIter = ParentStruct.Fields.begin() + OldFields;
45344564
FieldIter != ParentStruct.Fields.end(); ++FieldIter) {
4535-
FieldIter->Offset += ParentStruct.Size;
4565+
FieldIter->Offset += FirstFieldOffset;
45364566
}
4537-
}
45384567

4539-
if (ParentStruct.IsUnion)
4540-
ParentStruct.Size = std::max(ParentStruct.Size, Structure.Size);
4541-
else
4542-
ParentStruct.Size += Structure.Size;
4568+
const unsigned StructureEnd = FirstFieldOffset + Structure.Size;
4569+
if (!ParentStruct.IsUnion) {
4570+
ParentStruct.NextOffset = StructureEnd;
4571+
}
4572+
ParentStruct.Size = std::max(ParentStruct.Size, StructureEnd);
4573+
}
45434574
} else {
45444575
FieldInfo &Field = ParentStruct.addField(Structure.Name, FT_STRUCT,
45454576
Structure.AlignmentSize);
@@ -4548,10 +4579,11 @@ bool MasmParser::parseDirectiveNestedEnds() {
45484579
Field.LengthOf = 1;
45494580
Field.SizeOf = Structure.Size;
45504581

4551-
if (ParentStruct.IsUnion)
4552-
ParentStruct.Size = std::max(ParentStruct.Size, Field.SizeOf);
4553-
else
4554-
ParentStruct.Size += Field.SizeOf;
4582+
const unsigned StructureEnd = Field.Offset + Field.SizeOf;
4583+
if (!ParentStruct.IsUnion) {
4584+
ParentStruct.NextOffset = StructureEnd;
4585+
}
4586+
ParentStruct.Size = std::max(ParentStruct.Size, StructureEnd);
45554587

45564588
StructInfo.Structure = Structure;
45574589
StructInfo.Initializers.emplace_back();
@@ -4565,22 +4597,66 @@ bool MasmParser::parseDirectiveNestedEnds() {
45654597
}
45664598

45674599
/// parseDirectiveOrg
4568-
/// ::= .org expression [ , expression ]
4600+
/// ::= org expression
45694601
bool MasmParser::parseDirectiveOrg() {
45704602
const MCExpr *Offset;
45714603
SMLoc OffsetLoc = Lexer.getLoc();
45724604
if (checkForValidSection() || parseExpression(Offset))
45734605
return true;
4574-
4575-
// Parse optional fill expression.
4576-
int64_t FillExpr = 0;
4577-
if (parseOptionalToken(AsmToken::Comma))
4578-
if (parseAbsoluteExpression(FillExpr))
4579-
return addErrorSuffix(" in '.org' directive");
45804606
if (parseToken(AsmToken::EndOfStatement))
4581-
return addErrorSuffix(" in '.org' directive");
4607+
return addErrorSuffix(" in 'org' directive");
4608+
4609+
if (StructInProgress.empty()) {
4610+
// Not in a struct; change the offset for the next instruction or data
4611+
if (checkForValidSection())
4612+
return addErrorSuffix(" in 'org' directive");
4613+
4614+
getStreamer().emitValueToOffset(Offset, 0, OffsetLoc);
4615+
} else {
4616+
// Offset the next field of this struct
4617+
StructInfo &Structure = StructInProgress.back();
4618+
int64_t OffsetRes;
4619+
if (!Offset->evaluateAsAbsolute(OffsetRes, getStreamer().getAssemblerPtr()))
4620+
return Error(OffsetLoc,
4621+
"expected absolute expression in 'org' directive");
4622+
if (OffsetRes < 0)
4623+
return Error(
4624+
OffsetLoc,
4625+
"expected non-negative value in struct's 'org' directive; was " +
4626+
std::to_string(OffsetRes));
4627+
Structure.NextOffset = static_cast<unsigned>(OffsetRes);
4628+
4629+
// ORG-affected structures cannot be initialized
4630+
Structure.Initializable = false;
4631+
}
4632+
4633+
return false;
4634+
}
4635+
4636+
bool MasmParser::emitAlignTo(int64_t Alignment) {
4637+
if (StructInProgress.empty()) {
4638+
// Not in a struct; align the next instruction or data
4639+
if (checkForValidSection())
4640+
return true;
4641+
4642+
// Check whether we should use optimal code alignment for this align
4643+
// directive.
4644+
const MCSection *Section = getStreamer().getCurrentSectionOnly();
4645+
assert(Section && "must have section to emit alignment");
4646+
if (Section->UseCodeAlign()) {
4647+
getStreamer().emitCodeAlignment(Alignment, /*MaxBytesToEmit=*/0);
4648+
} else {
4649+
// FIXME: Target specific behavior about how the "extra" bytes are filled.
4650+
getStreamer().emitValueToAlignment(Alignment, /*Value=*/0,
4651+
/*ValueSize=*/1,
4652+
/*MaxBytesToEmit=*/0);
4653+
}
4654+
} else {
4655+
// Align the next field of this struct
4656+
StructInfo &Structure = StructInProgress.back();
4657+
Structure.NextOffset = llvm::alignTo(Structure.NextOffset, Alignment);
4658+
}
45824659

4583-
getStreamer().emitValueToOffset(Offset, FillExpr, OffsetLoc);
45844660
return false;
45854661
}
45864662

@@ -4590,8 +4666,6 @@ bool MasmParser::parseDirectiveAlign() {
45904666
SMLoc AlignmentLoc = getLexer().getLoc();
45914667
int64_t Alignment;
45924668

4593-
if (checkForValidSection())
4594-
return addErrorSuffix(" in align directive");
45954669
// Ignore empty 'align' directives.
45964670
if (getTok().is(AsmToken::EndOfStatement)) {
45974671
return Warning(AlignmentLoc,
@@ -4602,31 +4676,32 @@ bool MasmParser::parseDirectiveAlign() {
46024676
parseToken(AsmToken::EndOfStatement))
46034677
return addErrorSuffix(" in align directive");
46044678

4605-
// Always emit an alignment here even if we thrown an error.
4679+
// Always emit an alignment here even if we throw an error.
46064680
bool ReturnVal = false;
46074681

4608-
// Reject alignments that aren't either a power of two or zero, for gas
4682+
// Reject alignments that aren't either a power of two or zero, for ML.exe
46094683
// compatibility. Alignment of zero is silently rounded up to one.
46104684
if (Alignment == 0)
46114685
Alignment = 1;
46124686
if (!isPowerOf2_64(Alignment))
4613-
ReturnVal |= Error(AlignmentLoc, "alignment must be a power of 2");
4614-
4615-
// Check whether we should use optimal code alignment for this align
4616-
// directive.
4617-
const MCSection *Section = getStreamer().getCurrentSectionOnly();
4618-
assert(Section && "must have section to emit alignment");
4619-
if (Section->UseCodeAlign()) {
4620-
getStreamer().emitCodeAlignment(Alignment, /*MaxBytesToEmit=*/0);
4621-
} else {
4622-
// FIXME: Target specific behavior about how the "extra" bytes are filled.
4623-
getStreamer().emitValueToAlignment(Alignment, /*Value=*/0, /*ValueSize=*/1,
4624-
/*MaxBytesToEmit=*/0);
4625-
}
4687+
ReturnVal |= Error(AlignmentLoc, "alignment must be a power of 2; was " +
4688+
std::to_string(Alignment));
4689+
4690+
if (emitAlignTo(Alignment))
4691+
ReturnVal |= addErrorSuffix(" in align directive");
46264692

46274693
return ReturnVal;
46284694
}
46294695

4696+
/// parseDirectiveEven
4697+
/// ::= even
4698+
bool MasmParser::parseDirectiveEven() {
4699+
if (parseToken(AsmToken::EndOfStatement) || emitAlignTo(2))
4700+
return addErrorSuffix(" in even directive");
4701+
4702+
return false;
4703+
}
4704+
46304705
/// parseDirectiveFile
46314706
/// ::= .file filename
46324707
/// ::= .file number [directory] filename [md5 checksum] [source source-text]
@@ -6520,7 +6595,8 @@ void MasmParser::initializeDirectiveKindMap() {
65206595
DirectiveKindMap["real8"] = DK_REAL8;
65216596
DirectiveKindMap["real10"] = DK_REAL10;
65226597
DirectiveKindMap["align"] = DK_ALIGN;
6523-
// DirectiveKindMap[".org"] = DK_ORG;
6598+
DirectiveKindMap["even"] = DK_EVEN;
6599+
DirectiveKindMap["org"] = DK_ORG;
65246600
DirectiveKindMap["extern"] = DK_EXTERN;
65256601
DirectiveKindMap["public"] = DK_PUBLIC;
65266602
// DirectiveKindMap[".comm"] = DK_COMM;

0 commit comments

Comments
 (0)