[cfe-dev] Trying to add new x86 return instruction.

Seth Goldstein via cfe-dev cfe-dev at lists.llvm.org
Wed Oct 25 11:26:18 PDT 2017


TL;DR: I am trying to implement a new calling convention for X86 with
an associated new return instruction.  I am getting stuck with the
error listed towards the end and not sure where I need to make a
change.  I have included the changes I have made.  Any help is appreciated.

(In addition to finding out how to get past this error, I also would
love a pointer on how to generate a two-byte opcode for my new
instruction, e.g., 0xF0 0x3F.  In the code below you can see that I am
currently just generating 0xF0.  Thank-you.)

The rest of the note is:
- Overview of changes I made to clang
- Overview of changes I made to llvm
- C file I am trying to compile
- Error I get from executing llc
- The llvm IR for the C file
- The detailed list of changes I made to llvm
- The detailed list of changes I made to clang

- OVERVIEW OF CHANGES I MADE TO CLANG

In the front-end I added a new attribute: `__attribute__
((new_interrupt))`.  I am fairly confident I touched all the places I
needed to, but all the changes I made in Attr.td, SemaDeclAttr.cpp,
SemaExpr.cpp, AttrDocs.td, and DiagnosticSemaKinds.td are listed at
the very end under 'CHANGES TO CLANG:'

- OVERVIEW OF CHANGES I MADE TO LLVM

In llvm I am sure I have either made incorrect changes or am still
missing changes I need to make.  The overview is I added new defs for
my new X86 instructions, a new calling convention, code to detect the
attribute, and some new asm and LL tokens.  Yet, when I compile:

- C FILE I AM TRYING TO COMPILE

----------------------------------------------------------------
static int myvar = 0;

__attribute__ ((new_interrupt)) void
incr(void)
{
  myvar++;
}
----------------------------------------------------------------

- ERROR I GET FROM EXECUTING LLC

with `build/bin/llc one.ll` I get the following error (clearly I still
have to fix or implement something else)
----------------------------------------------------------------
llc: lib/Target/X86/X86GenAsmWriter.inc:45898: void
llvm::X86ATTInstPrinter::printInstruction(const llvm::MCInst*,
llvm::raw_ostream&): Assertion `Bits != 0 && "Cannot print this
instruction."' failed.
#0 0x00007fa28495ac59 llvm::sys::PrintStackTrace(llvm::raw_ostream&)
/home/seth/research/uli/src/compiler/llvm/lib/Support/Unix/Signals.inc:398:0
#1 0x00007fa28495acea PrintStackTraceSignalHandler(void*)
/home/seth/research/uli/src/compiler/llvm/lib/Support/Unix/Signals.inc:462:0
#2 0x00007fa2849590d8 llvm::sys::RunSignalHandlers()
/home/seth/research/uli/src/compiler/llvm/lib/Support/Signals.cpp:49:0
#3 0x00007fa28495a5f1 SignalHandler(int)
/home/seth/research/uli/src/compiler/llvm/lib/Support/Unix/Signals.inc:252:0
#4 0x00007fa2838a7cb0 (/lib/x86_64-linux-gnu/libc.so.6+0x36cb0)
#5 0x00007fa2838a7c37 gsignal
/build/eglibc-SvCtMH/eglibc-2.19/signal/../nptl/sysdeps/unix/sysv/linux/raise.c:56:0
#6 0x00007fa2838ab028 abort
/build/eglibc-SvCtMH/eglibc-2.19/stdlib/abort.c:91:0
#7 0x00007fa2838a0bf6 __assert_fail_base
/build/eglibc-SvCtMH/eglibc-2.19/assert/assert.c:92:0
#8 0x00007fa2838a0ca2 (/lib/x86_64-linux-gnu/libc.so.6+0x2fca2)
#9 0x00007fa2836c0bb1
llvm::X86ATTInstPrinter::printInstruction(llvm::MCInst const*,
llvm::raw_ostream&)
/home/seth/research/uli/src/compiler/build/lib/Target/X86/X86GenAsmWriter.inc:45899:0
#10 0x00007fa2836c4f6f llvm::X86ATTInstPrinter::printInst(llvm::MCInst
const*, llvm::raw_ostream&, llvm::StringRef, llvm::MCSubtargetInfo const&)
/home/seth/research/uli/src/compiler/llvm/lib/Target/X86/InstPrinter/X86ATTInstPrinter.cpp:95:0
#11 0x00007fa28595d7d0
llvm::MCTargetStreamer::prettyPrintAsm(llvm::MCInstPrinter&,
llvm::raw_ostream&, llvm::MCInst const&, llvm::MCSubtargetInfo const&)
/home/seth/research/uli/src/compiler/llvm/lib/MC/MCStreamer.cpp:832:0
#12 0x00007fa2858f6e7a (anonymous
namespace)::MCAsmStreamer::EmitInstruction(llvm::MCInst const&,
llvm::MCSubtargetInfo const&, bool)
/home/seth/research/uli/src/compiler/llvm/lib/MC/MCAsmStreamer.cpp:1659:0
#13 0x00007fa2887208ce
llvm::X86AsmPrinter::EmitAndCountInstruction(llvm::MCInst&)
/home/seth/research/uli/src/compiler/llvm/lib/Target/X86/X86MCInstLower.cpp:107:0
#14 0x00007fa28872a707
llvm::X86AsmPrinter::EmitInstruction(llvm::MachineInstr const*)
/home/seth/research/uli/src/compiler/llvm/lib/Target/X86/X86MCInstLower.cpp:2022:0
#15 0x00007fa2871d36db llvm::AsmPrinter::EmitFunctionBody()
/home/seth/research/uli/src/compiler/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp:1044:0
#16 0x00007fa288484d17
llvm::X86AsmPrinter::runOnMachineFunction(llvm::MachineFunction&)
/home/seth/research/uli/src/compiler/llvm/lib/Target/X86/X86AsmPrinter.cpp:81:0
#17 0x00007fa2868d35d3
llvm::MachineFunctionPass::runOnFunction(llvm::Function&)
/home/seth/research/uli/src/compiler/llvm/lib/CodeGen/MachineFunctionPass.cpp:62:0
#18 0x00007fa285e531f0 llvm::FPPassManager::runOnFunction(llvm::Function&)
/home/seth/research/uli/src/compiler/llvm/lib/IR/LegacyPassManager.cpp:1514:0
#19 0x00007fa285e53383 llvm::FPPassManager::runOnModule(llvm::Module&)
/home/seth/research/uli/src/compiler/llvm/lib/IR/LegacyPassManager.cpp:1535:0
#20 0x00007fa285e5371e (anonymous
namespace)::MPPassManager::runOnModule(llvm::Module&)
/home/seth/research/uli/src/compiler/llvm/lib/IR/LegacyPassManager.cpp:1591:0
#21 0x00007fa285e53e6e llvm::legacy::PassManagerImpl::run(llvm::Module&)
/home/seth/research/uli/src/compiler/llvm/lib/IR/LegacyPassManager.cpp:1694:0
#22 0x00007fa285e540af llvm::legacy::PassManager::run(llvm::Module&)
/home/seth/research/uli/src/compiler/llvm/lib/IR/LegacyPassManager.cpp:1726:0
#23 0x0000000000431826 compileModule(char**, llvm::LLVMContext&)
/home/seth/research/uli/src/compiler/llvm/tools/llc/llc.cpp:572:0
#24 0x000000000042ffd8 main
/home/seth/research/uli/src/compiler/llvm/tools/llc/llc.cpp:346:0
#25 0x00007fa283892f45 __libc_start_main
/build/eglibc-SvCtMH/eglibc-2.19/csu/libc-start.c:321:0
#26 0x000000000042de99 _start
(/home/seth/research/uli/src/compiler/build/bin/llc+0x42de99)
Stack dump:
0.      Program arguments: build/bin/llc one.ll
1.      Running pass 'Function Pass Manager' on module 'one.ll'.
2.      Running pass 'X86 Assembly Printer' on function '@incr'
Aborted (core dumped)
================================================================

- THE LLVM IR FOR THE C FILE

The llvm ir for the C file above is:
----------------------------------------------------------------
; ModuleID = 'one.c'
source_filename = "one.c"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

@myvar = internal global i32 0, align 4

; Function Attrs: noinline nounwind optnone uwtable
define x86_newircc void @incr() #0 {
entry:
  %0 = load i32, i32* @myvar, align 4
  %inc = add nsw i32 %0, 1
  store i32 %inc, i32* @myvar, align 4
  ret void
}

attributes #0 = { noinline nounwind optnone uwtable
"correctly-rounded-divide-sqrt-fp-math"="false"
"disable-tail-calls"="false" "less-precise-fpmad"="false"
"no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf"
"no-infs-fp-math"="false" "no-jump-tables"="false"
"no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false"
"no-trapping-math"="false" "stack-protector-buffer-size"="8"
"target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87"
"unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.module.flags = !{!0}
!llvm.ident = !{!1}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{!"clang version 6.0.0 (trunk) (llvm/trunk 316096)"}
----------------------------------------------------------------

- THE DETAILED LIST OF CHANGES I MADE TO LLVM


================================================================
Changes to llvm:
================================================================

llvm/include/llvm/IR/CallingConv.h:223
---------------------------------------------------------------- in
namespace CallingConv to the enum:
    /// X86_NewI - x86 new interrupt context. Callee may take
    /// multiple arguments which are accessed by the FROMNewI
    /// instructions
    X86_NewI = 97,
================================================================

llvm/lib/Target/X86/X86InstrInfo.td:2841
----------------------------------------------------------------
def : MnemonicAlias<"newiret",    "NewIRET",    "att">;
================================================================

llvm/lib/Target/X86/X86InstrControl.td:57
----------------------------------------------------------------
  // new interrupt return
  def NewIRET32   : I   <0x0F, RawFrm, (outs), (ins),
                    "newiretl", [], IIC_RET>, OpSize32;
  def NewIRET64   : I   <0x0F, RawFrm, (outs), (ins),
                    "newiretq", [], IIC_RET>, Requires<[In64BitMode]>;
----------------------------------------------------------------

llvm/lib/Target/X86/X86InstrControl.td:66
----------------------------------------------------------------
  let isCodeGenOnly = 1 in {
    def IRET : PseudoI<(outs), (ins i32imm:$adj), [(X86iret timm:$adj)]>;
    def NewIRET : PseudoI<(outs), (ins i32imm:$adj), [(X86newiret
timm:$adj)]>;
  }
================================================================

llvm/lib/Target/X86/X86ISelLowering.h:132
---------------------------------------------------------------- in
namespace X86ISD, enum NodeType
      /// Return from new interrupt. No operands
      NewIRET,
================================================================

llvm/lib/Target/X86/X86ISelLowering.cpp:2171
----------------------------------------- SDValue
X86TargetLowering::LowerReturn
  if (((CallConv == CallingConv::X86_INTR)||(CallConv ==
CallingConv::X86_NewI)) && !Outs.empty())
    report_fatal_error("X86 (new) interrupts may not return any value");
----------------------------------------

llvm/lib/Target/X86/X86ISelLowering.cpp:2358
----------------------------------------- SDValue
X86TargetLowering::LowerReturn
  else if (CallConv == CallingConv::X86_NewI)
    opcode = X86ISD::NewIRET;
----------------------------------------

llvm/lib/Target/X86/X86ISelLowering.cpp:3337
---------------------------------------------------------------- SDValue
X86TargetLowering::LowerCall
  else if (CallConv == CallingConv::X86_NewI)
    report_fatal_error("X86 new interrupts may not be called directly");
----------------------------------------

llvm/lib/Target/X86/X86ISelLowering.cpp:24539
---------------------------------------- const char
*X86TargetLowering::getTargetNodeName
  case X86ISD::NewIRET:             return "X86ISD::NewIRET";
================================================================

llvm/lib/AsmParser/LLToken.h:152
---------------------------------------------------------------- in
namespace lltok, enum kind
  kw_x86_newircc,
================================================================

llvm/lib/AsmParser/LLLexer.h:600
---------------------------------------------------------------- in
lltok::Kind LLLexer::LexIdentifier
  KEYWORD(x86_newircc);
================================================================

llvm/lib/AsmParser/LLParser.cpp:1737
---------------------------------------------------------------- in bool
LLParser::ParseOptionalCallingConv
  case lltok::kw_x86_newircc:        CC = CallingConv::X86_NewI; break;
================================================================

llvm/lib/IR/AsmWriter.cpp:373
---------------------------------------------------------------- in static
void PrintCallingConv
  case CallingConv::X86_NewI:      Out << "x86_newircc"; break;
================================================================

- THE DETAILED LIST OF CHANGES I MADE TO CLANG

CHANGES TO CLANG:
================================================================

clang/include/clang/Basic/Attr.td
---------------------------------------------------------------- Added new
def
 def NewInterrupt : InheritableAttr, TargetSpecificAttr<TargetAnyX86> {
  let Spellings = [GNU<"new_interrupt">];
  let Subjects = SubjectList<[Function]>;
  let Documentation = [NewInterruptDocs];
}
================================================================

clang/lib/Sema/SemaDeclAttr.cpp
---------------------------------------------------------------- Added In
static void ProcessDeclAttribute
  case AttributeList::AT_NewInterrupt:
    handleNewInterruptAttr(S, D, Attr);
    break;

---------------------------------------------------------------- Added new
function
static void handleNewInterruptAttr(Sema &S, Decl *D,
                                      const AttributeList &Attr) {
  // Semantic checks for a function with the 'interrupt' attribute.
  // a) Must be a function.
  // b) Must have the 'void' return type.

  if (!isFunctionOrMethod(D)) {
    S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
        << "'new-interrupt'" << ExpectedFunctionOrMethod;
    return;
  }

  if (!getFunctionOrMethodResultType(D)->isVoidType()) {
    S.Diag(D->getLocation(), diag::err_new_interrupt_attribute)
        << 1;
    return;
  }
  handleSimpleAttribute<NewInterruptAttr>(S, D, Attr);
}
================================================================

clang/lib/CodeGen/TargetInfo.cpp
------------------------------------------- Added In void
X86_32TargetCodeGenInfo::setTargetAttributes
    if (FD->hasAttr<AnyX86InterruptAttr>() ||
FD->hasAttr<NewInterruptAttr>()) {
      llvm::Function *Fn = cast<llvm::Function>(GV);
      Fn->setCallingConv(FD->hasAttr<AnyX86InterruptAttr>()
            ? llvm::CallingConv::X86_INTR
            : llvm::CallingConv::X86_NewI);
    }

------------------------------------------- Added In class
X86_64TargetCodeGenInfo, void setTargetAttributes
same as above

------------------------------------------- Added In void
WinX86_64TargetCodeGenInfo::setTargetAttributes
same as above
================================================================

In clang/lib/Sema/SemaExpr.cpp
---------------------------------------------------------------- Added In
ExprResult Sema::BuildResolvedCallExpr
  // Functions with 'interrupt' attribute cannot be called directly.
  if (FDecl && (FDecl->hasAttr<AnyX86InterruptAttr>() ||
FDecl->hasAttr<NewInterruptAttr>())) {
    Diag(Fn->getExprLoc(), diag::err_anyx86_interrupt_called);
    return ExprError();
  }
================================================================

In clang/include/clang/Basic/DiagnosticSemaKinds.td
---------------------------------------------------------------- Added new
defs
def err_new_interrupt_attribute : Error<
    "'new_interrupt' attribute only applies to functions that have a 'void'
return type">;
def err_new_interrupt_called : Error<
  "new interrupt service routine cannot be called directly">;
================================================================

In clang/include/clang/Basic/AttrDocs.td
---------------------------------------------------------------- Added new
def
def NewInterruptDocs  : Documentation {
  let Category = DocCatFunction;
  let Heading = "new interrupt (x86)";
  let Content = [{
Clang supports the GNU style ``__attribute__((new_interrupt))`` attribute on
x86 targets. This attribute may be attached to a function definition and
instructs the backend to generate appropriate function entry/exit code so
that
it can be used directly as a new interrupt service routine.
  }];
}
================================================================


--------------
Seth Copen Goldstein
Carnegie Mellon University
Computer Science Dept
7111 GHC
412-268-3828
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20171025/fe368ea2/attachment.html>


More information about the cfe-dev mailing list