diff --git a/llvm/include/llvm/MC/MCParser/MCAsmParser.h b/llvm/include/llvm/MC/MCParser/MCAsmParser.h --- a/llvm/include/llvm/MC/MCParser/MCAsmParser.h +++ b/llvm/include/llvm/MC/MCParser/MCAsmParser.h @@ -90,6 +90,20 @@ IdKind Kind; }; +// Generic type information for an assembly object. +// All sizes measured in bytes. +struct AsmTypeInfo { + StringRef Name; + unsigned Size = 0; + unsigned ElementSize = 0; + unsigned Length = 0; +}; + +struct AsmFieldInfo { + AsmTypeInfo Type; + unsigned Offset = 0; +}; + /// Generic Sema callback for assembly parser. class MCAsmParserSemaCallback { public: @@ -170,12 +184,15 @@ virtual bool isParsingMasm() const { return false; } - virtual bool lookUpField(StringRef Name, StringRef &Type, - unsigned &Offset) const { + virtual bool lookUpField(StringRef Name, AsmFieldInfo &Info) const { return true; } - virtual bool lookUpField(StringRef Base, StringRef Member, StringRef &Type, - unsigned &Offset) const { + virtual bool lookUpField(StringRef Base, StringRef Member, + AsmFieldInfo &Info) const { + return true; + } + + virtual bool lookUpType(StringRef Name, AsmTypeInfo &Info) const { return true; } @@ -281,7 +298,8 @@ /// \param Res - The value of the expression. The result is undefined /// on error. /// \return - False on success. - virtual bool parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) = 0; + virtual bool parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc, + AsmTypeInfo *TypeInfo) = 0; /// Parse an arbitrary expression, assuming that an initial '(' has /// already been consumed. diff --git a/llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h b/llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h --- a/llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h +++ b/llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h @@ -370,7 +370,7 @@ // Target-specific parsing of expression. virtual bool parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { - return getParser().parsePrimaryExpr(Res, EndLoc); + return getParser().parsePrimaryExpr(Res, EndLoc, nullptr); } virtual bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp --- a/llvm/lib/MC/MCParser/AsmParser.cpp +++ b/llvm/lib/MC/MCParser/AsmParser.cpp @@ -244,7 +244,8 @@ bool parseExpression(const MCExpr *&Res); bool parseExpression(const MCExpr *&Res, SMLoc &EndLoc) override; - bool parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) override; + bool parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc, + AsmTypeInfo *TypeInfo) override; bool parseParenExpression(const MCExpr *&Res, SMLoc &EndLoc) override; bool parseParenExprOfDepth(unsigned ParenDepth, const MCExpr *&Res, SMLoc &EndLoc) override; @@ -1068,7 +1069,8 @@ /// primaryexpr ::= number /// primaryexpr ::= '.' /// primaryexpr ::= ~,+,- primaryexpr -bool AsmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { +bool AsmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc, + AsmTypeInfo *TypeInfo) { SMLoc FirstTokenLoc = getLexer().getLoc(); AsmToken::TokenKind FirstTokenKind = Lexer.getKind(); switch (FirstTokenKind) { @@ -1079,7 +1081,7 @@ return true; case AsmToken::Exclaim: Lex(); // Eat the operator. - if (parsePrimaryExpr(Res, EndLoc)) + if (parsePrimaryExpr(Res, EndLoc, TypeInfo)) return true; Res = MCUnaryExpr::createLNot(Res, getContext(), FirstTokenLoc); return false; @@ -1238,19 +1240,19 @@ return parseBracketExpr(Res, EndLoc); case AsmToken::Minus: Lex(); // Eat the operator. - if (parsePrimaryExpr(Res, EndLoc)) + if (parsePrimaryExpr(Res, EndLoc, TypeInfo)) return true; Res = MCUnaryExpr::createMinus(Res, getContext(), FirstTokenLoc); return false; case AsmToken::Plus: Lex(); // Eat the operator. - if (parsePrimaryExpr(Res, EndLoc)) + if (parsePrimaryExpr(Res, EndLoc, TypeInfo)) return true; Res = MCUnaryExpr::createPlus(Res, getContext(), FirstTokenLoc); return false; case AsmToken::Tilde: Lex(); // Eat the operator. - if (parsePrimaryExpr(Res, EndLoc)) + if (parsePrimaryExpr(Res, EndLoc, TypeInfo)) return true; Res = MCUnaryExpr::createNot(Res, getContext(), FirstTokenLoc); return false; diff --git a/llvm/lib/MC/MCParser/MasmParser.cpp b/llvm/lib/MC/MCParser/MasmParser.cpp --- a/llvm/lib/MC/MCParser/MasmParser.cpp +++ b/llvm/lib/MC/MCParser/MasmParser.cpp @@ -20,6 +20,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" @@ -122,14 +123,14 @@ struct StructInfo { StringRef Name; bool IsUnion = false; - size_t Alignment = 0; - size_t Size = 0; - size_t AlignmentSize = 0; + unsigned Alignment = 0; + unsigned Size = 0; + unsigned AlignmentSize = 0; std::vector Fields; StringMap FieldsByName; FieldInfo &addField(StringRef FieldName, FieldType FT, - size_t FieldAlignmentSize); + unsigned FieldAlignmentSize); StructInfo() = default; @@ -319,13 +320,13 @@ size_t Offset = 0; // Total size of the field (= LengthOf * Type). - size_t SizeOf = 0; + unsigned SizeOf = 0; // Number of elements in the field (1 if scalar, >1 if an array). - size_t LengthOf = 0; + unsigned LengthOf = 0; // Size of a single entry in this field, in bytes ("type" in MASM standards). - size_t Type = 0; + unsigned Type = 0; FieldInitializer Contents; @@ -333,9 +334,9 @@ }; FieldInfo &StructInfo::addField(StringRef FieldName, FieldType FT, - size_t FieldAlignmentSize) { + unsigned FieldAlignmentSize) { if (!FieldName.empty()) - FieldsByName[FieldName] = Fields.size(); + FieldsByName[FieldName.lower()] = Fields.size(); Fields.emplace_back(FT); FieldInfo &Field = Fields.back(); if (IsUnion) { @@ -390,8 +391,8 @@ /// Maps struct tags to struct definitions. StringMap Structs; - /// Maps data location names to user-defined types. - StringMap KnownType; + /// Maps data location names to types. + StringMap KnownType; /// Stack of active macro instantiations. std::vector ActiveMacros; @@ -494,10 +495,11 @@ bool isParsingMasm() const override { return true; } - bool lookUpField(StringRef Name, StringRef &Type, - unsigned &Offset) const override; - bool lookUpField(StringRef Base, StringRef Member, StringRef &Type, - unsigned &Offset) const override; + bool lookUpField(StringRef Name, AsmFieldInfo &Info) const override; + bool lookUpField(StringRef Base, StringRef Member, + AsmFieldInfo &Info) const override; + + bool lookUpType(StringRef Name, AsmTypeInfo &Info) const override; bool parseMSInlineAsm(void *AsmLoc, std::string &AsmString, unsigned &NumOutputs, unsigned &NumInputs, @@ -509,7 +511,8 @@ bool parseExpression(const MCExpr *&Res); bool parseExpression(const MCExpr *&Res, SMLoc &EndLoc) override; - bool parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) override; + bool parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc, + AsmTypeInfo *TypeInfo) override; bool parseParenExpression(const MCExpr *&Res, SMLoc &EndLoc) override; bool parseParenExprOfDepth(unsigned ParenDepth, const MCExpr *&Res, SMLoc &EndLoc) override; @@ -568,7 +571,7 @@ static void DiagHandler(const SMDiagnostic &Diag, void *Context); bool lookUpField(const StructInfo &Structure, StringRef Member, - StringRef &Type, unsigned &Offset) const; + AsmFieldInfo &Info) const; /// Should we emit DWARF describing this assembler source? (Returns false if /// the source has .file directives, which means we don't want to generate @@ -756,23 +759,24 @@ bool parseScalarInstList( unsigned Size, SmallVectorImpl &Values, const AsmToken::TokenKind EndToken = AsmToken::EndOfStatement); - bool emitIntegralValues(unsigned Size); + bool emitIntegralValues(unsigned Size, unsigned *Count = nullptr); bool addIntegralField(StringRef Name, unsigned Size); bool parseDirectiveValue(StringRef IDVal, unsigned Size); - bool parseDirectiveNamedValue(StringRef IDVal, unsigned Size, StringRef Name, - SMLoc NameLoc); + bool parseDirectiveNamedValue(StringRef TypeName, unsigned Size, + StringRef Name, SMLoc NameLoc); // "real4", "real8" - bool emitRealValues(const fltSemantics &Semantics); + bool emitRealValues(const fltSemantics &Semantics, unsigned *Count = nullptr); bool addRealField(StringRef Name, const fltSemantics &Semantics, size_t Size); bool parseDirectiveRealValue(StringRef IDVal, const fltSemantics &Semantics, size_t Size); bool parseRealInstList( const fltSemantics &Semantics, SmallVectorImpl &Values, const AsmToken::TokenKind EndToken = AsmToken::EndOfStatement); - bool parseDirectiveNamedRealValue(StringRef IDVal, - const fltSemantics &Semantics, size_t Size, - StringRef Name, SMLoc NameLoc); + bool parseDirectiveNamedRealValue(StringRef TypeName, + const fltSemantics &Semantics, + unsigned Size, StringRef Name, + SMLoc NameLoc); bool parseOptionalAngleBracketOpen(); bool parseAngleBracketClose(const Twine &Msg = "expected '>'"); @@ -816,7 +820,7 @@ const StructInitializer &Initializer); // User-defined types (structs, unions): - bool emitStructValues(const StructInfo &Structure); + bool emitStructValues(const StructInfo &Structure, unsigned *Count = nullptr); bool addStructField(StringRef Name, const StructInfo &Structure); bool parseDirectiveStructValue(const StructInfo &Structure, StringRef Directive, SMLoc DirLoc); @@ -1321,7 +1325,8 @@ /// primaryexpr ::= number /// primaryexpr ::= '.' /// primaryexpr ::= ~,+,-,'not' primaryexpr -bool MasmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { +bool MasmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc, + AsmTypeInfo *TypeInfo) { SMLoc FirstTokenLoc = getLexer().getLoc(); AsmToken::TokenKind FirstTokenKind = Lexer.getKind(); switch (FirstTokenKind) { @@ -1332,7 +1337,7 @@ return true; case AsmToken::Exclaim: Lex(); // Eat the operator. - if (parsePrimaryExpr(Res, EndLoc)) + if (parsePrimaryExpr(Res, EndLoc, nullptr)) return true; Res = MCUnaryExpr::createLNot(Res, getContext(), FirstTokenLoc); return false; @@ -1360,7 +1365,7 @@ } // Parse named bitwise negation. if (Identifier.equals_lower("not")) { - if (parsePrimaryExpr(Res, EndLoc)) + if (parsePrimaryExpr(Res, EndLoc, nullptr)) return true; Res = MCUnaryExpr::createNot(Res, getContext(), FirstTokenLoc); return false; @@ -1415,24 +1420,19 @@ } // Find the field offset if used. - StringRef Type; - unsigned Offset = 0; + AsmFieldInfo Info; Split = SymbolName.split('.'); - if (!Split.second.empty()) { + if (Split.second.empty()) { + } else { SymbolName = Split.first; - if (Structs.count(SymbolName.lower()) && - !lookUpField(SymbolName, Split.second, Type, Offset)) { - // This is actually a reference to a field offset. - Res = MCConstantExpr::create(Offset, getContext()); - return false; - } - - auto TypeIt = KnownType.find(SymbolName); - if (TypeIt == KnownType.end() || - lookUpField(*TypeIt->second, Split.second, Type, Offset)) { + if (lookUpField(SymbolName, Split.second, Info)) { std::pair BaseMember = Split.second.split('.'); StringRef Base = BaseMember.first, Member = BaseMember.second; - lookUpField(Base, Member, Type, Offset); + lookUpField(Base, Member, Info); + } else if (Structs.count(SymbolName.lower())) { + // This is actually a reference to a field offset. + Res = MCConstantExpr::create(Info.Offset, getContext()); + return false; } } @@ -1458,13 +1458,23 @@ // Otherwise create a symbol ref. const MCExpr *SymRef = MCSymbolRefExpr::create(Sym, Variant, getContext(), FirstTokenLoc); - if (Offset) { - Res = MCBinaryExpr::create(MCBinaryExpr::Add, SymRef, - MCConstantExpr::create(Offset, getContext()), - getContext()); + if (Info.Offset) { + Res = MCBinaryExpr::create( + MCBinaryExpr::Add, SymRef, + MCConstantExpr::create(Info.Offset, getContext()), getContext()); } else { Res = SymRef; } + if (TypeInfo) { + if (Info.Type.Name.empty()) { + auto TypeIt = KnownType.find(Identifier.lower()); + if (TypeIt != KnownType.end()) { + Info.Type = TypeIt->second; + } + } + + *TypeInfo = Info.Type; + } return false; } case AsmToken::BigNum: @@ -1528,19 +1538,19 @@ return parseBracketExpr(Res, EndLoc); case AsmToken::Minus: Lex(); // Eat the operator. - if (parsePrimaryExpr(Res, EndLoc)) + if (parsePrimaryExpr(Res, EndLoc, nullptr)) return true; Res = MCUnaryExpr::createMinus(Res, getContext(), FirstTokenLoc); return false; case AsmToken::Plus: Lex(); // Eat the operator. - if (parsePrimaryExpr(Res, EndLoc)) + if (parsePrimaryExpr(Res, EndLoc, nullptr)) return true; Res = MCUnaryExpr::createPlus(Res, getContext(), FirstTokenLoc); return false; case AsmToken::Tilde: Lex(); // Eat the operator. - if (parsePrimaryExpr(Res, EndLoc)) + if (parsePrimaryExpr(Res, EndLoc, nullptr)) return true; Res = MCUnaryExpr::createNot(Res, getContext(), FirstTokenLoc); return false; @@ -3309,7 +3319,7 @@ return false; } -bool MasmParser::emitIntegralValues(unsigned Size) { +bool MasmParser::emitIntegralValues(unsigned Size, unsigned *Count) { SmallVector Values; if (checkForValidSection() || parseScalarInstList(Size, Values)) return true; @@ -3317,6 +3327,8 @@ for (auto Value : Values) { emitIntValue(Value, Size); } + if (Count) + *Count = Values.size(); return false; } @@ -3356,16 +3368,24 @@ /// parseDirectiveNamedValue /// ::= name (byte | word | ... ) [ expression (, expression)* ] -bool MasmParser::parseDirectiveNamedValue(StringRef IDVal, unsigned Size, +bool MasmParser::parseDirectiveNamedValue(StringRef TypeName, unsigned Size, StringRef Name, SMLoc NameLoc) { if (StructInProgress.empty()) { // Initialize named data value. MCSymbol *Sym = getContext().getOrCreateSymbol(Name); getStreamer().emitLabel(Sym); - if (emitIntegralValues(Size)) - return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); + unsigned Count; + if (emitIntegralValues(Size, &Count)) + return addErrorSuffix(" in '" + Twine(TypeName) + "' directive"); + + AsmTypeInfo Type; + Type.Name = TypeName; + Type.Size = Size * Count; + Type.ElementSize = Size; + Type.Length = Count; + KnownType[Name.lower()] = Type; } else if (addIntegralField(Name, Size)) { - return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); + return addErrorSuffix(" in '" + Twine(TypeName) + "' directive"); } return false; @@ -3482,7 +3502,8 @@ } // Initialize real data values. -bool MasmParser::emitRealValues(const fltSemantics &Semantics) { +bool MasmParser::emitRealValues(const fltSemantics &Semantics, + unsigned *Count) { if (checkForValidSection()) return true; @@ -3494,6 +3515,8 @@ getStreamer().emitIntValue(AsInt.getLimitedValue(), AsInt.getBitWidth() / 8); } + if (Count) + *Count = ValuesAsInt.size(); return false; } @@ -3536,18 +3559,26 @@ /// parseDirectiveNamedRealValue /// ::= name (real4 | real8) [ expression (, expression)* ] -bool MasmParser::parseDirectiveNamedRealValue(StringRef IDVal, +bool MasmParser::parseDirectiveNamedRealValue(StringRef TypeName, const fltSemantics &Semantics, - size_t Size, StringRef Name, + unsigned Size, StringRef Name, SMLoc NameLoc) { if (StructInProgress.empty()) { // Initialize named data value. MCSymbol *Sym = getContext().getOrCreateSymbol(Name); getStreamer().emitLabel(Sym); - if (emitRealValues(Semantics)) - return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); + unsigned Count; + if (emitRealValues(Semantics, &Count)) + return addErrorSuffix(" in '" + TypeName + "' directive"); + + AsmTypeInfo Type; + Type.Name = TypeName; + Type.Size = Size * Count; + Type.ElementSize = Size; + Type.Length = Count; + KnownType[Name.lower()] = Type; } else if (addRealField(Name, Semantics, Size)) { - return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); + return addErrorSuffix(" in '" + TypeName + "' directive"); } return false; } @@ -3960,7 +3991,8 @@ } // Set data values from initializers. -bool MasmParser::emitStructValues(const StructInfo &Structure) { +bool MasmParser::emitStructValues(const StructInfo &Structure, + unsigned *Count) { std::vector Initializers; if (parseStructInstList(Structure, Initializers)) return true; @@ -3970,6 +4002,8 @@ return true; } + if (Count) + *Count = Initializers.size(); return false; } @@ -4020,9 +4054,15 @@ // Initialize named data value. MCSymbol *Sym = getContext().getOrCreateSymbol(Name); getStreamer().emitLabel(Sym); - KnownType[Name] = &Structure; - if (emitStructValues(Structure)) + unsigned Count; + if (emitStructValues(Structure, &Count)) return true; + AsmTypeInfo Type; + Type.Name = Structure.Name; + Type.Size = Structure.Size * Count; + Type.ElementSize = Structure.Size; + Type.Length = Count; + KnownType[Name.lower()] = Type; } else if (addStructField(Name, Structure)) { return addErrorSuffix(" in '" + Twine(Directive) + "' directive"); } @@ -6564,37 +6604,39 @@ llvm_unreachable("Unstable rewrite sort."); } -bool MasmParser::lookUpField(StringRef Name, StringRef &Type, - unsigned &Offset) const { +bool MasmParser::lookUpField(StringRef Name, AsmFieldInfo &Info) const { const std::pair BaseMember = Name.split('.'); const StringRef Base = BaseMember.first, Member = BaseMember.second; - return lookUpField(Base, Member, Type, Offset); + return lookUpField(Base, Member, Info); } -bool MasmParser::lookUpField(StringRef Base, StringRef Member, StringRef &Type, - unsigned &Offset) const { +bool MasmParser::lookUpField(StringRef Base, StringRef Member, + AsmFieldInfo &Info) const { if (Base.empty()) return true; - unsigned BaseOffset = 0; - if (Base.contains('.') && !lookUpField(Base, Type, BaseOffset)) - Base = Type; - - auto TypeIt = KnownType.find(Base); - if (TypeIt != KnownType.end()) - return lookUpField(*TypeIt->second, Member, Type, Offset); + AsmFieldInfo BaseInfo; + if (Base.contains('.') && !lookUpField(Base, BaseInfo)) + Base = BaseInfo.Type.Name; auto StructIt = Structs.find(Base.lower()); + auto TypeIt = KnownType.find(Base.lower()); + if (TypeIt != KnownType.end()) { + StructIt = Structs.find(TypeIt->second.Name.lower()); + } if (StructIt != Structs.end()) - return lookUpField(StructIt->second, Member, Type, Offset); + return lookUpField(StructIt->second, Member, Info); return true; } bool MasmParser::lookUpField(const StructInfo &Structure, StringRef Member, - StringRef &Type, unsigned &Offset) const { + AsmFieldInfo &Info) const { if (Member.empty()) { - Type = Structure.Name; + Info.Type.Name = Structure.Name; + Info.Type.Size = Structure.Size; + Info.Type.ElementSize = Structure.Size; + Info.Type.Length = 1; return false; } @@ -6603,7 +6645,7 @@ auto StructIt = Structs.find(FieldName.lower()); if (StructIt != Structs.end()) - return lookUpField(StructIt->second, FieldMember, Type, Offset); + return lookUpField(StructIt->second, FieldMember, Info); auto FieldIt = Structure.FieldsByName.find(FieldName.lower()); if (FieldIt == Structure.FieldsByName.end()) @@ -6611,9 +6653,12 @@ const FieldInfo &Field = Structure.Fields[FieldIt->second]; if (FieldMember.empty()) { - Offset += Field.Offset; + Info.Offset += Field.Offset; + Info.Type.Size = Field.SizeOf; + Info.Type.ElementSize = Field.Type; + Info.Type.Length = Field.LengthOf; if (Field.Contents.FT == FT_STRUCT) - Type = Field.Contents.StructInfo.Structure.Name; + Info.Type.Name = Field.Contents.StructInfo.Structure.Name; return false; } @@ -6621,14 +6666,44 @@ return true; const StructFieldInfo &StructInfo = Field.Contents.StructInfo; - bool Result = lookUpField(StructInfo.Structure, FieldMember, Type, Offset); - if (Result) + if (lookUpField(StructInfo.Structure, FieldMember, Info)) return true; - Offset += Field.Offset; + Info.Offset += Field.Offset; return false; } +bool MasmParser::lookUpType(StringRef Name, AsmTypeInfo &Info) const { + unsigned Size = StringSwitch(Name) + .CasesLower("byte", "db", "sbyte", 1) + .CasesLower("word", "dw", "sword", 2) + .CasesLower("dword", "dd", "sdword", 4) + .CasesLower("fword", "df", 6) + .CasesLower("qword", "dq", "sqword", 8) + .CaseLower("real4", 4) + .CaseLower("real8", 8) + .Default(0); + if (Size) { + Info.Name = Name; + Info.ElementSize = Size; + Info.Length = 1; + Info.Size = Size; + return false; + } + + auto StructIt = Structs.find(Name.lower()); + if (StructIt != Structs.end()) { + const StructInfo &Structure = StructIt->second; + Info.Name = Name; + Info.ElementSize = Structure.Size; + Info.Length = 1; + Info.Size = Structure.Size; + return false; + } + + return true; +} + bool MasmParser::parseMSInlineAsm( void *AsmLoc, std::string &AsmString, unsigned &NumOutputs, unsigned &NumInputs, SmallVectorImpl> &OpDecls, diff --git a/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp b/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp --- a/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp +++ b/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp @@ -2541,7 +2541,7 @@ // This syntax is not compatible with syntax of standard // MC expressions (due to the trailing '|'). SMLoc EndLoc; - if (getParser().parsePrimaryExpr(Expr, EndLoc)) + if (getParser().parsePrimaryExpr(Expr, EndLoc, nullptr)) return MatchOperand_ParseFail; } else { if (Parser.parseExpression(Expr)) diff --git a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp --- a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp +++ b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -32,6 +32,7 @@ #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" @@ -150,6 +151,13 @@ IOK_TYPE, }; + enum MasmOperatorKind { + MOK_INVALID = 0, + MOK_LENGTHOF, + MOK_SIZEOF, + MOK_TYPE, + }; + class InfixCalculator { typedef std::pair< InfixCalculatorTok, int64_t > ICToken; SmallVector InfixOperatorStack; @@ -367,7 +375,7 @@ bool MemExpr; bool OffsetOperator; SMLoc OffsetOperatorLoc; - StringRef CurType; + AsmTypeInfo CurType; bool setSymRef(const MCExpr *Val, StringRef ID, StringRef &ErrMsg) { if (Sym) { @@ -395,7 +403,10 @@ unsigned getScale() { return Scale; } const MCExpr *getSym() { return Sym; } StringRef getSymName() { return SymName; } - StringRef getType() { return CurType; } + StringRef getType() { return CurType.Name; } + unsigned getSize() { return CurType.Size; } + unsigned getElementSize() { return CurType.ElementSize; } + unsigned getLength() { return CurType.Length; } int64_t getImm() { return Imm + IC.execute(); } bool isValidEndState() { return State == IES_RBRAC || State == IES_INTEGER; @@ -628,7 +639,8 @@ } bool onIdentifierExpr(const MCExpr *SymRef, StringRef SymRefName, const InlineAsmIdentifierInfo &IDInfo, - bool ParsingMSInlineAsm, StringRef &ErrMsg) { + const AsmTypeInfo &Type, bool ParsingMSInlineAsm, + StringRef &ErrMsg) { // InlineAsm: Treat an enum value as an integer if (ParsingMSInlineAsm) if (IDInfo.isKind(InlineAsmIdentifierInfo::IK_EnumVal)) @@ -647,6 +659,7 @@ case IES_NOT: case IES_INIT: case IES_LBRAC: + case IES_LPAREN: if (setSymRef(SymRef, SymRefName, ErrMsg)) return true; MemExpr = true; @@ -654,6 +667,7 @@ IC.pushOperand(IC_IMM); if (ParsingMSInlineAsm) Info = IDInfo; + setTypeInfo(Type); break; } return false; @@ -752,6 +766,8 @@ case IES_RPAREN: State = IES_PLUS; IC.pushOperator(IC_PLUS); + CurType.Length = 1; + CurType.Size = CurType.ElementSize; break; case IES_INIT: case IES_CAST: @@ -835,8 +851,8 @@ } } bool onOffset(const MCExpr *Val, SMLoc OffsetLoc, StringRef ID, - const InlineAsmIdentifierInfo &IDInfo, bool ParsingMSInlineAsm, - StringRef &ErrMsg) { + const InlineAsmIdentifierInfo &IDInfo, + bool ParsingMSInlineAsm, StringRef &ErrMsg) { PrevState = State; switch (State) { default: @@ -860,19 +876,19 @@ } return false; } - void onCast(StringRef Type) { + void onCast(AsmTypeInfo Info) { PrevState = State; switch (State) { default: State = IES_ERROR; break; case IES_LPAREN: - setType(Type); + setTypeInfo(Info); State = IES_CAST; break; } } - void setType(StringRef Type) { CurType = Type; } + void setTypeInfo(AsmTypeInfo Type) { CurType = Type; } }; bool Error(SMLoc L, const Twine &Msg, SMRange Range = None, @@ -909,6 +925,8 @@ bool ParseIntelDotOperator(IntelExprStateMachine &SM, SMLoc &End); unsigned IdentifyIntelInlineAsmOperator(StringRef Name); unsigned ParseIntelInlineAsmOperator(unsigned OpKind); + unsigned IdentifyMasmOperator(StringRef Name); + bool ParseMasmOperator(unsigned OpKind, int64_t &Val); bool ParseRoundingModeOp(SMLoc Start, OperandVector &Operands); bool ParseIntelNamedOperator(StringRef Name, IntelExprStateMachine &SM, bool &ParseError, SMLoc &End); @@ -1653,6 +1671,13 @@ if (ParseIntelDotOperator(SM, End)) return true; break; + case AsmToken::Dollar: + if (!Parser.isParsingMasm()) { + if ((Done = SM.isValidEndState())) + break; + return Error(Tok.getLoc(), "unknown token in expression"); + } + LLVM_FALLTHROUGH; case AsmToken::At: case AsmToken::String: case AsmToken::Identifier: { @@ -1664,7 +1689,10 @@ const AsmToken &NextTok = getLexer().peekTok(); if (NextTok.is(AsmToken::Identifier) && NextTok.getIdentifier().equals_lower("ptr")) { - SM.onCast(Identifier); + AsmTypeInfo Info; + if (Parser.lookUpType(Identifier, Info)) + return Error(Tok.getLoc(), "unknown type"); + SM.onCast(Info); // Eat type and PTR. consumeToken(); End = consumeToken(); @@ -1689,16 +1717,15 @@ if (SM.onRegister(Reg, ErrMsg)) return Error(IdentLoc, ErrMsg); - StringRef Type; - unsigned Offset = 0; + AsmFieldInfo Info; SMLoc FieldStartLoc = SMLoc::getFromPointer(Field.data()); - if (Parser.lookUpField(Field, Type, Offset)) + if (Parser.lookUpField(Field, Info)) return Error(FieldStartLoc, "unknown offset"); else if (SM.onPlus(ErrMsg)) return Error(getTok().getLoc(), ErrMsg); - else if (SM.onInteger(Offset, ErrMsg)) + else if (SM.onInteger(Info.Offset, ErrMsg)) return Error(IdentLoc, ErrMsg); - SM.setType(Type); + SM.setTypeInfo(Info.Type); End = consumeToken(); break; @@ -1714,6 +1741,7 @@ } // Symbol reference, when parsing assembly content InlineAsmIdentifierInfo Info; + AsmTypeInfo Type; const MCExpr *Val; if (isParsingMSInlineAsm() || Parser.isParsingMasm()) { // MS Dot Operator expression @@ -1740,13 +1768,24 @@ return Error(IdentLoc, "expected identifier"); if (ParseIntelInlineAsmIdentifier(Val, Identifier, Info, false, End)) return true; - else if (SM.onIdentifierExpr(Val, Identifier, Info, true, ErrMsg)) + else if (SM.onIdentifierExpr(Val, Identifier, Info, Type, true, ErrMsg)) return Error(IdentLoc, ErrMsg); break; } - if (getParser().parsePrimaryExpr(Val, End)) { + if (Parser.isParsingMasm()) { + if (unsigned OpKind = IdentifyMasmOperator(Identifier)) { + int64_t Val; + if (ParseMasmOperator(OpKind, Val)) + return true; + if (SM.onInteger(Val, ErrMsg)) + return Error(IdentLoc, ErrMsg); + break; + } + } + if (getParser().parsePrimaryExpr(Val, End, &Type)) { return Error(Tok.getLoc(), "Unexpected identifier!"); - } else if (SM.onIdentifierExpr(Val, Identifier, Info, false, ErrMsg)) { + } else if (SM.onIdentifierExpr(Val, Identifier, Info, Type, false, + ErrMsg)) { return Error(IdentLoc, ErrMsg); } break; @@ -1769,8 +1808,9 @@ return Error(Loc, "invalid reference to undefined symbol"); StringRef Identifier = Sym->getName(); InlineAsmIdentifierInfo Info; - if (SM.onIdentifierExpr(Val, Identifier, Info, isParsingMSInlineAsm(), - ErrMsg)) + AsmTypeInfo Type; + if (SM.onIdentifierExpr(Val, Identifier, Info, Type, + isParsingMSInlineAsm(), ErrMsg)) return Error(Loc, ErrMsg); End = consumeToken(); } else { @@ -1957,8 +1997,7 @@ bool X86AsmParser::ParseIntelDotOperator(IntelExprStateMachine &SM, SMLoc &End) { const AsmToken &Tok = getTok(); - StringRef Type; - unsigned Offset = 0; + AsmFieldInfo Info; // Drop the optional '.'. StringRef DotDispStr = Tok.getString(); @@ -1969,27 +2008,28 @@ if (Tok.is(AsmToken::Real)) { APInt DotDisp; DotDispStr.getAsInteger(10, DotDisp); - Offset = DotDisp.getZExtValue(); + Info.Offset = DotDisp.getZExtValue(); } else if ((isParsingMSInlineAsm() || getParser().isParsingMasm()) && Tok.is(AsmToken::Identifier)) { const std::pair BaseMember = DotDispStr.split('.'); const StringRef Base = BaseMember.first, Member = BaseMember.second; - if (getParser().lookUpField(SM.getType(), DotDispStr, Type, Offset) && - getParser().lookUpField(SM.getSymName(), DotDispStr, Type, Offset) && - getParser().lookUpField(DotDispStr, Type, Offset) && + if (getParser().lookUpField(SM.getType(), DotDispStr, Info) && + getParser().lookUpField(SM.getSymName(), DotDispStr, Info) && + getParser().lookUpField(DotDispStr, Info) && (!SemaCallback || - SemaCallback->LookupInlineAsmField(Base, Member, Offset))) + SemaCallback->LookupInlineAsmField(Base, Member, Info.Offset))) return Error(Tok.getLoc(), "Unable to lookup field reference!"); - } else + } else { return Error(Tok.getLoc(), "Unexpected token type!"); + } // Eat the DotExpression and update End End = SMLoc::getFromPointer(DotDispStr.data()); const char *DotExprEndLoc = DotDispStr.data() + DotDispStr.size(); while (Tok.getLoc().getPointer() < DotExprEndLoc) Lex(); - SM.addImm(Offset); - SM.setType(Type); + SM.addImm(Info.Offset); + SM.setTypeInfo(Info.Type); return false; } @@ -2004,7 +2044,7 @@ if (!isParsingMSInlineAsm()) { if ((getTok().isNot(AsmToken::Identifier) && getTok().isNot(AsmToken::String)) || - getParser().parsePrimaryExpr(Val, End)) + getParser().parsePrimaryExpr(Val, End, nullptr)) return Error(Start, "unexpected token!"); } else if (ParseIntelInlineAsmIdentifier(Val, ID, Info, false, End, true)) { return Error(Start, "unable to lookup expression"); @@ -2059,6 +2099,73 @@ return CVal; } +// Query a candidate string for being an Intel assembly operator +// Report back its kind, or IOK_INVALID if does not evaluated as a known one +unsigned X86AsmParser::IdentifyMasmOperator(StringRef Name) { + return StringSwitch(Name.lower()) + .Case("type", MOK_TYPE) + .Cases("size", "sizeof", MOK_SIZEOF) + .Cases("length", "lengthof", MOK_LENGTHOF) + .Default(MOK_INVALID); +} + +/// Parse the 'LENGTHOF', 'SIZEOF', and 'TYPE' operators. The LENGTHOF operator +/// returns the number of elements in an array. It returns the value 1 for +/// non-array variables. The SIZEOF operator returns the size of a type or +/// variable in bytes. A variable's size is the product of its LENGTH and TYPE. +/// The TYPE operator returns the size of a variable. If the variable is an +/// array, TYPE returns the size of a single element. +bool X86AsmParser::ParseMasmOperator(unsigned OpKind, int64_t &Val) { + MCAsmParser &Parser = getParser(); + SMLoc OpLoc = Parser.getTok().getLoc(); + Parser.Lex(); // Eat operator. + + Val = 0; + if (OpKind == MOK_SIZEOF || OpKind == MOK_TYPE) { + // Check for SIZEOF() and TYPE(). + bool InParens = Parser.getTok().is(AsmToken::LParen); + const AsmToken &IDTok = InParens ? getLexer().peekTok() : Parser.getTok(); + AsmTypeInfo Type; + if (IDTok.is(AsmToken::Identifier) && + !Parser.lookUpType(IDTok.getIdentifier(), Type)) { + Val = Type.Size; + + // Eat tokens. + if (InParens) + parseToken(AsmToken::LParen); + parseToken(AsmToken::Identifier); + if (InParens) + parseToken(AsmToken::RParen); + } + } + + if (!Val) { + IntelExprStateMachine SM; + SMLoc End, Start = Parser.getTok().getLoc(); + if (ParseIntelExpression(SM, End)) + return true; + + switch (OpKind) { + default: + llvm_unreachable("Unexpected operand kind!"); + case MOK_SIZEOF: + Val = SM.getSize(); + break; + case MOK_LENGTHOF: + Val = SM.getLength(); + break; + case MOK_TYPE: + Val = SM.getElementSize(); + break; + } + + if (!Val) + return Error(OpLoc, "expression has unknown type", SMRange(Start, End)); + } + + return false; +} + bool X86AsmParser::ParseIntelMemoryOperandSize(unsigned &Size) { Size = StringSwitch(getTok().getString()) .Cases("BYTE", "byte", 8) @@ -2161,6 +2268,8 @@ unsigned BaseReg = SM.getBaseReg(); unsigned IndexReg = SM.getIndexReg(); unsigned Scale = SM.getScale(); + if (!PtrInOperand) + Size = SM.getElementSize() << 3; if (Scale == 0 && BaseReg != X86::ESP && BaseReg != X86::RSP && (IndexReg == X86::ESP || IndexReg == X86::RSP)) @@ -2617,7 +2726,7 @@ Res = X86MCExpr::create(RegNo, Parser.getContext()); return false; } - return Parser.parsePrimaryExpr(Res, EndLoc); + return Parser.parsePrimaryExpr(Res, EndLoc, nullptr); } bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, diff --git a/llvm/test/tools/llvm-ml/size_inference.test b/llvm/test/tools/llvm-ml/size_inference.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-ml/size_inference.test @@ -0,0 +1,27 @@ +; RUN: not llvm-ml -filetype=asm %s 2>&1 | FileCheck %s --dump-input=always + +.data + +FOO STRUCT + dword_field DWORD 3 + byte_field BYTE 4 DUP (1) +FOO ENDS + +var FOO <> + +.code + +t1 PROC + +mov eax, var.byte_field +; CHECK: error: invalid operand for instruction + +mov eax, [var].byte_field +; CHECK: error: invalid operand for instruction + +mov eax, [var.byte_field] +; CHECK: error: invalid operand for instruction + +t1 ENDP + +END diff --git a/llvm/test/tools/llvm-ml/struct.test b/llvm/test/tools/llvm-ml/struct.test --- a/llvm/test/tools/llvm-ml/struct.test +++ b/llvm/test/tools/llvm-ml/struct.test @@ -78,70 +78,70 @@ .code t3: -mov eax, t2.f.h -mov eax, [t2].f.h -mov eax, [t2.f.h] +mov al, t2.f.h +mov al, [t2].f.h +mov al, [t2.f.h] ; CHECK: t3: -; CHECK-NEXT: mov eax, dword ptr [rip + t2+11] -; CHECK-NEXT: mov eax, dword ptr [rip + t2+11] -; CHECK-NEXT: mov eax, dword ptr [rip + t2+11] +; CHECK-NEXT: mov al, byte ptr [rip + t2+11] +; CHECK-NEXT: mov al, byte ptr [rip + t2+11] +; CHECK-NEXT: mov al, byte ptr [rip + t2+11] t4: -mov eax, j.FOOBAR.f.h -mov eax, j.baz.b +mov al, j.FOOBAR.f.h +mov al, j.baz.b ; CHECK: t4: -; CHECK-NEXT: mov eax, dword ptr [rip + j+11] -; CHECK-NEXT: mov eax, dword ptr [rip + j+1] +; CHECK-NEXT: mov al, byte ptr [rip + j+11] +; CHECK-NEXT: mov al, byte ptr [rip + j+1] t5: -mov eax, [ebx].FOOBAR.f.h -mov eax, [ebx.FOOBAR].f.h -mov eax, [ebx.FOOBAR.f.h] +mov al, [ebx].FOOBAR.f.h +mov al, [ebx.FOOBAR].f.h +mov al, [ebx.FOOBAR.f.h] ; CHECK: t5: -; CHECK-NEXT: mov eax, dword ptr [ebx + 11] -; CHECK-NEXT: mov eax, dword ptr [ebx + 11] -; CHECK-NEXT: mov eax, dword ptr [ebx + 11] +; CHECK-NEXT: mov al, byte ptr [ebx + 11] +; CHECK-NEXT: mov al, byte ptr [ebx + 11] +; CHECK-NEXT: mov al, byte ptr [ebx + 11] t6: -mov eax, t2.FOOBAR.f.h -mov eax, [t2].FOOBAR.f.h -mov eax, [t2.FOOBAR].f.h -mov eax, [t2.FOOBAR.f.h] +mov al, t2.FOOBAR.f.h +mov al, [t2].FOOBAR.f.h +mov al, [t2.FOOBAR].f.h +mov al, [t2.FOOBAR.f.h] ; CHECK: t6: -; CHECK-NEXT: mov eax, dword ptr [rip + t2+11] -; CHECK-NEXT: mov eax, dword ptr [rip + t2+11] -; CHECK-NEXT: mov eax, dword ptr [rip + t2+11] -; CHECK-NEXT: mov eax, dword ptr [rip + t2+11] +; CHECK-NEXT: mov al, byte ptr [rip + t2+11] +; CHECK-NEXT: mov al, byte ptr [rip + t2+11] +; CHECK-NEXT: mov al, byte ptr [rip + t2+11] +; CHECK-NEXT: mov al, byte ptr [rip + t2+11] t7: -mov eax, [ebx].FOOBAR.e.b -mov eax, [ebx.FOOBAR].e.b -mov eax, [ebx.FOOBAR.e].b -mov eax, [ebx.FOOBAR.e.b] +mov al, [ebx].FOOBAR.e.b +mov al, [ebx.FOOBAR].e.b +mov al, [ebx.FOOBAR.e].b +mov al, [ebx.FOOBAR.e.b] ; CHECK: t7: -; CHECK-NEXT: mov eax, dword ptr [ebx + 9] -; CHECK-NEXT: mov eax, dword ptr [ebx + 9] -; CHECK-NEXT: mov eax, dword ptr [ebx + 9] -; CHECK-NEXT: mov eax, dword ptr [ebx + 9] +; CHECK-NEXT: mov al, byte ptr [ebx + 9] +; CHECK-NEXT: mov al, byte ptr [ebx + 9] +; CHECK-NEXT: mov al, byte ptr [ebx + 9] +; CHECK-NEXT: mov al, byte ptr [ebx + 9] t8: -mov eax, t2.FOOBAR.e.b -mov eax, [t2].FOOBAR.e.b -mov eax, [t2.FOOBAR].e.b -mov eax, [t2.FOOBAR.e].b -mov eax, [t2.FOOBAR.e.b] +mov al, t2.FOOBAR.e.b +mov al, [t2].FOOBAR.e.b +mov al, [t2.FOOBAR].e.b +mov al, [t2.FOOBAR.e].b +mov al, [t2.FOOBAR.e.b] ; CHECK: t8: -; CHECK-NEXT: mov eax, dword ptr [rip + t2+9] -; CHECK-NEXT: mov eax, dword ptr [rip + t2+9] -; CHECK-NEXT: mov eax, dword ptr [rip + t2+9] -; CHECK-NEXT: mov eax, dword ptr [rip + (t2+8)+1] -; CHECK-NEXT: mov eax, dword ptr [rip + t2+9] +; CHECK-NEXT: mov al, byte ptr [rip + t2+9] +; CHECK-NEXT: mov al, byte ptr [rip + t2+9] +; CHECK-NEXT: mov al, byte ptr [rip + t2+9] +; CHECK-NEXT: mov al, byte ptr [rip + (t2+8)+1] +; CHECK-NEXT: mov al, byte ptr [rip + t2+9] QUUX STRUCT u DWORD ? @@ -159,20 +159,20 @@ t9: mov eax, [ebx].QUUX.u -mov eax, [ebx].QUUX.v +mov ax, [ebx].QUUX.v mov eax, [ebx].QUUX.w -mov eax, [ebx].QUUX.x -mov eax, [ebx].QUUX.y -mov eax, [ebx].QUUX.after_struct +mov al, [ebx].QUUX.x +mov al, [ebx].QUUX.y +mov al, [ebx].QUUX.after_struct mov eax, [ebx].QUUX.z ; CHECK: t9: ; CHECK-NEXT: mov eax, dword ptr [ebx] +; CHECK-NEXT: mov ax, word ptr [ebx + 4] ; CHECK-NEXT: mov eax, dword ptr [ebx + 4] -; CHECK-NEXT: mov eax, dword ptr [ebx + 4] -; CHECK-NEXT: mov eax, dword ptr [ebx + 4] -; CHECK-NEXT: mov eax, dword ptr [ebx + 5] -; CHECK-NEXT: mov eax, dword ptr [ebx + 4] +; CHECK-NEXT: mov al, byte ptr [ebx + 4] +; CHECK-NEXT: mov al, byte ptr [ebx + 5] +; CHECK-NEXT: mov al, byte ptr [ebx + 4] ; CHECK-NEXT: mov eax, dword ptr [ebx + 8] t10: @@ -184,11 +184,11 @@ ; CHECK-NEXT: mov eax, 11 t11: -mov eax, (FOOBAR PTR [ebx]).f -mov eax, (FOOBAR PTR t1).f +mov ax, (FOOBAR PTR [ebx]).f +mov ax, (FOOBAR PTR t1).f ; CHECK: t11: -; CHECK-NEXT: mov eax, dword ptr [ebx + 10] -; CHECK-NEXT: mov eax, dword ptr [rip + t1+10] +; CHECK-NEXT: mov ax, word ptr [ebx + 10] +; CHECK-NEXT: mov ax, word ptr [rip + t1+10] END diff --git a/llvm/test/tools/llvm-ml/type_operators.test b/llvm/test/tools/llvm-ml/type_operators.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-ml/type_operators.test @@ -0,0 +1,237 @@ +# RUN: llvm-ml -filetype=asm %s | FileCheck %s + +.data + +FOO STRUCT 2 + x BYTE ? + y WORD 5 DUP (?) +FOO ENDS + +.code + +t1: +; CHECK-LABEL: t1: + +mov eax, sizeof BYTE +mov eax, (sizeof sBYTE) +mov eax, sizeof(Db) +mov eax, type BYTE +mov eax, (type sBYTE) +mov eax, type(Db) +; CHECK: mov eax, 1 +; CHECK: mov eax, 1 +; CHECK: mov eax, 1 +; CHECK: mov eax, 1 +; CHECK: mov eax, 1 +; CHECK: mov eax, 1 + +mov eax, sizeof(word) +mov eax, type(word) +; CHECK: mov eax, 2 +; CHECK: mov eax, 2 +mov eax, sizeof(dword) +mov eax, type(dword) +; CHECK: mov eax, 4 +; CHECK: mov eax, 4 +mov eax, sizeof(fword) +mov eax, type(fword) +; CHECK: mov eax, 6 +; CHECK: mov eax, 6 +mov eax, sizeof(qword) +mov eax, type(qword) +; CHECK: mov eax, 8 +; CHECK: mov eax, 8 + +mov eax, sizeof(real4) +mov eax, type(real4) +; CHECK: mov eax, 4 +; CHECK: mov eax, 4 +mov eax, sizeof(real8) +mov eax, type(real8) +; CHECK: mov eax, 8 +; CHECK: mov eax, 8 + +mov eax, sizeof(FOO) +mov eax, type(FOO) +; CHECK: mov eax, 12 +; CHECK: mov eax, 12 + + +t2_full BYTE "ab" +t2_short DB ? +t2_signed SBYTE 3 DUP (?) + +t2: +; CHECK-LABEL: t2: + +mov eax, sizeof(t2_full) +mov eax, lengthof(t2_full) +mov eax, type(t2_full) +; CHECK: mov eax, 2 +; CHECK: mov eax, 2 +; CHECK: mov eax, 1 + +mov eax, sizeof(t2_short) +mov eax, lengthof(t2_short) +mov eax, type(t2_short) +; CHECK: mov eax, 1 +; CHECK: mov eax, 1 +; CHECK: mov eax, 1 + +mov eax, sizeof(t2_signed) +mov eax, lengthof(t2_signed) +mov eax, type(t2_signed) +; CHECK: mov eax, 3 +; CHECK: mov eax, 3 +; CHECK: mov eax, 1 + + +t3_full WORD 2 DUP (?) +t3_short DW ? +t3_signed SWORD 3 DUP (?) + +t3: +; CHECK-LABEL: t3: + +mov eax, sizeof(t3_full) +mov eax, lengthof(t3_full) +mov eax, type(t3_full) +; CHECK: mov eax, 4 +; CHECK: mov eax, 2 +; CHECK: mov eax, 2 + +mov eax, sizeof(t3_short) +mov eax, lengthof(t3_short) +mov eax, type(t3_short) +; CHECK: mov eax, 2 +; CHECK: mov eax, 1 +; CHECK: mov eax, 2 + +mov eax, sizeof(t3_signed) +mov eax, lengthof(t3_signed) +mov eax, type(t3_signed) +; CHECK: mov eax, 6 +; CHECK: mov eax, 3 +; CHECK: mov eax, 2 + + +t4_full DWORD 2 DUP (?) +t4_short DD ? +t4_signed SDWORD 3 DUP (?) + +t4: +; CHECK-LABEL: t4: + +mov eax, sizeof(t4_full) +mov eax, lengthof(t4_full) +mov eax, type(t4_full) +; CHECK: mov eax, 8 +; CHECK: mov eax, 2 +; CHECK: mov eax, 4 + +mov eax, sizeof(t4_short) +mov eax, lengthof(t4_short) +mov eax, type(t4_short) +; CHECK: mov eax, 4 +; CHECK: mov eax, 1 +; CHECK: mov eax, 4 + +mov eax, sizeof(t4_signed) +mov eax, lengthof(t4_signed) +mov eax, type(t4_signed) +; CHECK: mov eax, 12 +; CHECK: mov eax, 3 +; CHECK: mov eax, 4 + + +t5_full FWORD 2 DUP (?) +t5_short DF ? + +t5: +; CHECK-LABEL: t5: + +mov eax, sizeof(t5_full) +mov eax, lengthof(t5_full) +mov eax, type(t5_full) +; CHECK: mov eax, 12 +; CHECK: mov eax, 2 +; CHECK: mov eax, 6 + +mov eax, sizeof(t5_short) +mov eax, lengthof(t5_short) +mov eax, type(t5_short) +; CHECK: mov eax, 6 +; CHECK: mov eax, 1 +; CHECK: mov eax, 6 + + +t6_full QWORD 2 DUP (?) +t6_short DQ ? +t6_signed SQWORD 3 DUP (?) + +t6: +; CHECK-LABEL: t6: + +mov eax, sizeof(t6_full) +mov eax, lengthof(t6_full) +mov eax, type(t6_full) +; CHECK: mov eax, 16 +; CHECK: mov eax, 2 +; CHECK: mov eax, 8 + +mov eax, sizeof(t6_short) +mov eax, lengthof(t6_short) +mov eax, type(t6_short) +; CHECK: mov eax, 8 +; CHECK: mov eax, 1 +; CHECK: mov eax, 8 + +mov eax, sizeof(t6_signed) +mov eax, lengthof(t6_signed) +mov eax, type(t6_signed) +; CHECK: mov eax, 24 +; CHECK: mov eax, 3 +; CHECK: mov eax, 8 + + +t7_single REAL4 2 DUP (?) +t7_double REAL8 ? + +t7: +; CHECK-LABEL: t7: + +mov eax, sizeof(t7_single) +mov eax, lengthof(t7_single) +mov eax, type(t7_single) +; CHECK: mov eax, 8 +; CHECK: mov eax, 2 +; CHECK: mov eax, 4 + +mov eax, sizeof(t7_double) +mov eax, lengthof(t7_double) +mov eax, type(t7_double) +; CHECK: mov eax, 8 +; CHECK: mov eax, 1 +; CHECK: mov eax, 8 + + +t8_var FOO <>, <> + +t8: +; CHECK-LABEL: t8: + +mov eax, sizeof(t8_var) +mov eax, lengthof(t8_var) +mov eax, type(t8_var) +; CHECK: mov eax, 24 +; CHECK: mov eax, 2 +; CHECK: mov eax, 12 + +mov eax, sizeof(t8_var.y) +mov eax, lengthof(t8_var.y) +mov eax, type(t8_var.y) +; CHECK: mov eax, 10 +; CHECK: mov eax, 5 +; CHECK: mov eax, 2 + +END