[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